/// <summary> /// Initializes a new instance of the <see cref="StopRequestException"/> class. /// </summary> /// <param name="finalStatus"> /// The final status. /// </param> /// <param name="message"> /// The message. /// </param> /// <param name="throwable"> /// The throwable. /// </param> public StopRequestException(ExpansionDownloadStatus finalStatus, string message, Exception throwable = null) : base(message, throwable) { Debug.WriteLine(message); this.FinalStatus = finalStatus; }
/// <summary> /// Called just before the thread finishes, regardless of status, to take any /// necessary action on the downloaded file. /// </summary> /// <param name="state"> /// The state. /// </param> /// <param name="finalStatus"> /// The final Status. /// </param> private static void CleanupDestination(State state, ExpansionDownloadStatus finalStatus) { CloseDestination(state); if (state.Filename != null && finalStatus.IsError() && File.Exists(state.Filename)) { File.Delete(state.Filename); state.Filename = null; } }
/// <summary> /// Stores information about the completed download, and notifies the initiating application. /// </summary> /// <param name="status"> /// The status. /// </param> /// <param name="countRetry"> /// The count Retry. /// </param> /// <param name="retryAfter"> /// The retry After. /// </param> /// <param name="redirectCount"> /// The redirect Count. /// </param> /// <param name="gotData"> /// The got Data. /// </param> private void NotifyDownloadCompleted( ExpansionDownloadStatus status, bool countRetry, int retryAfter, int redirectCount, bool gotData) { Debug.WriteLine("NotifyDownloadCompleted"); this.UpdateDownloadDatabase(status, countRetry, retryAfter, redirectCount, gotData); if (status.IsCompleted()) { // TBD: send status update? } }
/// <summary> /// The update metadata. /// </summary> /// <param name="apkVersion"> /// The apk version. /// </param> /// <param name="status"> /// The download status. /// </param> public static void UpdateMetadata(int apkVersion, ExpansionDownloadStatus status) { var metadata = XmlDatastore.GetData <MetadataTable>(); metadata.ApkVersion = apkVersion; metadata.DownloadStatus = status; XmlDatastore.SaveData(metadata); versionCode = apkVersion; downloadStatus = status; }
/// <summary> /// Initializes static members of the <see cref="DownloadsDatabase"/> class. /// </summary> static DownloadsDatabase() { downloadStatus = ExpansionDownloadStatus.Unknown; flags = 0; versionCode = -1; if (File.Exists(XmlDatastore.GetDataPath <MetadataTable>())) { downloadStatus = XmlDatastore.GetData <MetadataTable>().DownloadStatus; flags = XmlDatastore.GetData <MetadataTable>().Flags; versionCode = XmlDatastore.GetData <MetadataTable>().ApkVersion; } }
/// <summary> /// Starts the download if necessary. /// </summary> /// <remarks> /// This function starts a flow that /// does many things: /// 1) Checks to see if the APK version has been checked and the /// metadata database updated /// 2) If the APK version does not match, checks the new LVL status /// to see if a new download is required /// 3) If the APK version does match, then checks to see if the /// download(s) have been completed /// 4) If the downloads have been completed, returns /// <see cref="DownloadServiceRequirement.NoDownloadRequired"/> /// The idea is that this can be called during the startup of an /// application to quickly ascertain if the application needs to wait /// to hear about any updated APK expansion files. /// This does mean that the application MUST be run with a network /// connection for the first time, even if Market delivers all of the /// files. /// </remarks> /// <param name="context"> /// Your application Context. /// </param> /// <param name="pendingIntent"> /// A PendingIntent to start the Activity in your application that /// shows the download progress and which will also start the /// application when downloadcompletes. /// </param> /// <param name="serviceType"> /// The class of your <see cref="DownloaderService"/> implementation. /// </param> /// <returns> /// Whether the service was started and the reason for starting the /// service. /// Either <see cref="DownloadServiceRequirement.NoDownloadRequired"/>, /// <see cref="DownloadServiceRequirement.LvlCheckRequired"/>, or /// <see cref="DownloadServiceRequirement.DownloadRequired"/> /// </returns> public static DownloadServiceRequirement StartDownloadServiceIfRequired( Context context, PendingIntent pendingIntent, Type serviceType) { // first: do we need to do an LVL update? // we begin by getting our APK version from the package manager PackageInfo pi = context.PackageManager.GetPackageInfo(context.PackageName, 0); var status = DownloadServiceRequirement.NoDownloadRequired; // we need to update the LVL check and get a successful status to proceed if (IsLvlCheckRequired(pi)) { status = DownloadServiceRequirement.LvlCheckRequired; } // we don't have to update LVL. Do we still have a download to start? if (DownloadsDatabase.DownloadStatus == ExpansionDownloadStatus.None) { List <DownloadInfo> infos = DownloadsDatabase.GetDownloads(); IEnumerable <DownloadInfo> nonExisting = infos.Where(i => !Helpers.DoesFileExist(context, i.FileName, i.TotalBytes, true)); if (nonExisting.Any()) { status = DownloadServiceRequirement.DownloadRequired; DownloadsDatabase.DownloadStatus = ExpansionDownloadStatus.Unknown; } } else { status = DownloadServiceRequirement.DownloadRequired; } switch (status) { case DownloadServiceRequirement.DownloadRequired: case DownloadServiceRequirement.LvlCheckRequired: var fileIntent = new Intent(context.ApplicationContext, serviceType); fileIntent.PutExtra(DownloaderServiceExtras.PendingIntent, pendingIntent); context.StartService(fileIntent); break; } return(status); }
/// <summary> /// The update download database. /// </summary> /// <param name="status"> /// The status. /// </param> /// <param name="countRetry"> /// The count retry. /// </param> /// <param name="retryAfter"> /// The retry after. /// </param> /// <param name="redirectCount"> /// The redirect count. /// </param> /// <param name="gotData"> /// The got data. /// </param> private void UpdateDownloadDatabase( ExpansionDownloadStatus status, bool countRetry, int retryAfter, int redirectCount, bool gotData) { this.downloadInfo.Status = status; this.downloadInfo.RetryAfter = retryAfter; this.downloadInfo.RedirectCount = redirectCount; this.downloadInfo.LastModified = PolicyExtensions.GetCurrentMilliseconds(); if (!countRetry) { this.downloadInfo.FailedCount = 0; } else if (gotData) { this.downloadInfo.FailedCount = 1; } else { this.downloadInfo.FailedCount++; } DownloadsDatabase.UpdateDownload(this.downloadInfo); }
/// <summary> /// Returns whether the status is a success (i.e. 2xx). /// </summary> /// <param name="status"> /// The status. /// </param> /// <returns> /// The is status success. /// </returns> public static bool IsSuccess(this ExpansionDownloadStatus status) { return(status >= ExpansionDownloadStatus.SuccessMinimum && status <= ExpansionDownloadStatus.SuccessMaximum); }
/// <summary> /// Starts the download if necessary. /// </summary> /// <remarks> /// This function starts a flow that /// does many things: /// 1) Checks to see if the APK version has been checked and the /// metadata database updated /// 2) If the APK version does not match, checks the new LVL status /// to see if a new download is required /// 3) If the APK version does match, then checks to see if the /// download(s) have been completed /// 4) If the downloads have been completed, returns /// <see cref="DownloadServiceRequirement.NoDownloadRequired"/> /// The idea is that this can be called during the startup of an /// application to quickly ascertain if the application needs to wait /// to hear about any updated APK expansion files. /// This does mean that the application MUST be run with a network /// connection for the first time, even if Market delivers all of the /// files. /// </remarks> /// <param name="context"> /// Your application Context. /// </param> /// <param name="pendingIntent"> /// A PendingIntent to start the Activity in your application that /// shows the download progress and which will also start the /// application when downloadcompletes. /// </param> /// <param name="serviceType"> /// The class of your <see cref="DownloaderService"/> implementation. /// </param> /// <returns> /// Whether the service was started and the reason for starting the /// service. /// Either <see cref="DownloadServiceRequirement.NoDownloadRequired"/>, /// <see cref="DownloadServiceRequirement.LvlCheckRequired"/>, or /// <see cref="DownloadServiceRequirement.DownloadRequired"/> /// </returns> public static DownloadServiceRequirement StartDownloadServiceIfRequired( Context context, PendingIntent pendingIntent, Type serviceType) { // first: do we need to do an LVL update? // we begin by getting our APK version from the package manager PackageInfo pi = context.PackageManager.GetPackageInfo(context.PackageName, 0); var status = DownloadServiceRequirement.NoDownloadRequired; // we need to update the LVL check and get a successful status to proceed if (IsLvlCheckRequired(pi)) { status = DownloadServiceRequirement.LvlCheckRequired; } // we don't have to update LVL. Do we still have a download to start? if (DownloadsDatabase.DownloadStatus == ExpansionDownloadStatus.None) { List<DownloadInfo> infos = DownloadsDatabase.GetDownloads(); IEnumerable<DownloadInfo> nonExisting = infos.Where(i => !Helpers.DoesFileExist(context, i.FileName, i.TotalBytes, true)); if (nonExisting.Any()) { status = DownloadServiceRequirement.DownloadRequired; DownloadsDatabase.DownloadStatus = ExpansionDownloadStatus.Unknown; } } else { status = DownloadServiceRequirement.DownloadRequired; } switch (status) { case DownloadServiceRequirement.DownloadRequired: case DownloadServiceRequirement.LvlCheckRequired: var fileIntent = new Intent(context.ApplicationContext, serviceType); fileIntent.PutExtra(DownloaderServiceExtras.PendingIntent, pendingIntent); context.StartService(fileIntent); break; } return status; }
/// <summary> /// Initializes a new instance of the <see cref="GenerateSaveFileError"/> class. /// </summary> /// <param name="status"> /// The status. /// </param> /// <param name="message"> /// The message. /// </param> public GenerateSaveFileError(ExpansionDownloadStatus status, string message) : base(message) { this.Status = status; }
/// <summary> /// Returns whether the download has completed (either with success or /// error). /// </summary> /// <param name="status"> /// The status. /// </param> /// <returns> /// The is status completed. /// </returns> public static bool IsCompleted(this ExpansionDownloadStatus status) { return(status.IsSuccess() || status.IsError()); }
/// <summary> /// Returns whether the status is a redirect (i.e. 3xx). /// </summary> /// <param name="status"> /// The status. /// </param> /// <returns> /// The status a redirect. /// </returns> public static bool IsRedirect(this ExpansionDownloadStatus status) { return(status >= ExpansionDownloadStatus.RedirectMinimum && status <= ExpansionDownloadStatus.RedirectMaximum); }
/// <summary> /// Returns whether the status is informational (i.e. 1xx). /// </summary> /// <param name="status"> /// The status. /// </param> /// <returns> /// The is status informational. /// </returns> public static bool IsInformational(this ExpansionDownloadStatus status) { return(status >= ExpansionDownloadStatus.InformationalMinimum && status <= ExpansionDownloadStatus.InformationalMaximum); }
/// <summary> /// Returns whether the status is an error (i.e. 4xx or 5xx). /// </summary> /// <param name="status"> /// The status. /// </param> /// <returns> /// The is status error. /// </returns> public static bool IsError(this ExpansionDownloadStatus status) { return(status >= ExpansionDownloadStatus.AnyErrorMinimum && status <= ExpansionDownloadStatus.AnyErrorMaximum); }
/// <summary> /// The allow. /// </summary> /// <param name="reason"> /// The reason. /// </param> /// <exception cref="Java.Lang.RuntimeException"> /// Error with LVL checking and database integrity /// </exception> /// <exception cref="Java.Lang.RuntimeException"> /// Error with getting information from package name /// </exception> public void Allow(PolicyServerResponse reason) { try { int count = this.policy.GetExpansionFilesCount(); if (count == 0) { Debug.WriteLine("No expansion packs."); } ExpansionDownloadStatus status = 0; for (int index = 0; index < count; index++) { var type = (ApkExpansionPolicy.ExpansionFileType)index; ApkExpansionPolicy.ExpansionFile expansionFile = this.policy.GetExpansionFile(type); string currentFileName = expansionFile.FileName; if (currentFileName != null) { var di = new DownloadInfo { ExpansionFileType = type, FileName = currentFileName, }; if (this.Context.HandleFileUpdated(currentFileName, expansionFile.FileSize)) { status = ExpansionDownloadStatus.Unknown; di.ResetDownload(); di.Uri = expansionFile.Url; di.TotalBytes = expansionFile.FileSize; di.Status = status; DownloadsDatabase.UpdateDownload(di); } else { // we need to read the download information from the database DownloadInfo dbdi = DownloadsDatabase.GetDownloadInfo(di.FileName); if (dbdi == null) { // the file exists already and is the correct size // was delivered by Market or through another mechanism Debug.WriteLine(string.Format("file {0} found. Not downloading.", di.FileName)); di.Status = ExpansionDownloadStatus.Success; di.TotalBytes = expansionFile.FileSize; di.CurrentBytes = expansionFile.FileSize; di.Uri = expansionFile.Url; DownloadsDatabase.UpdateDownload(di); } else if (dbdi.Status != ExpansionDownloadStatus.Success) { // we just update the URL dbdi.Uri = expansionFile.Url; DownloadsDatabase.UpdateDownload(dbdi); status = ExpansionDownloadStatus.Unknown; } } } } // first: do we need to do an LVL update? // we begin by getting our APK version from the package manager try { PackageInfo pi = this.Context.PackageManager.GetPackageInfo(this.Context.PackageName, 0); DownloadsDatabase.UpdateMetadata(pi.VersionCode, status); DownloadServiceRequirement required = StartDownloadServiceIfRequired( this.Context, this.Context.pPendingIntent, this.Context.GetType()); switch (required) { case DownloadServiceRequirement.NoDownloadRequired: this.Context.downloadNotification.OnDownloadStateChanged(DownloaderState.Completed); break; case DownloadServiceRequirement.LvlCheckRequired: // DANGER WILL ROBINSON! Debug.WriteLine("In LVL checking loop!"); this.Context.downloadNotification.OnDownloadStateChanged( DownloaderState.FailedUnlicensed); throw new RuntimeException("Error with LVL checking and database integrity"); case DownloadServiceRequirement.DownloadRequired: // do nothing: the download will notify the application when things are done break; } } catch (PackageManager.NameNotFoundException e1) { e1.PrintStackTrace(); throw new RuntimeException("Error with getting information from package name"); } catch (Exception ex) { Debug.WriteLine("LVL Update Exception: " + ex.Message); throw; } } catch (Exception ex) { Debug.WriteLine("Allow Exception: " + ex.Message); throw; } finally { this.Context.IsServiceRunning = false; } }