Update progress from BackgroudDownloader when app is closed - c#

I am using BackgroundDownloader in my UWP app like:
private async void StartDownload()
{
var destinationFile = await KnownFolders.VideosLibrary.CreateFileAsync("temp.zip", CreationCollisionOption.GenerateUniqueName);
var backgroundDownloader = new BackgroundDownloader();
var downloadOperation = backgroundDownloader.CreateDownload(fileUrl, destinationFile);
SendUpdatableToastWithProgress();
var progressCallback = new Progress<DownloadOperation>();
progressCallback.ProgressChanged += ProgressCallback_ProgressChanged;
var opProgress = await downloadOperation.StartAsync().AsTask(progressCallback);
}
private void ProgressCallback_ProgressChanged(object sender, DownloadOperation e)
{
if (e.Progress.TotalBytesToReceive > 0)
{
var br = e.Progress.BytesReceived;
var percent = br * 1.0 / e.Progress.TotalBytesToReceive;
UpdateToastProgress(percent);
}
}
Is there any chance how can I get ProgressChanged fired even the UWP App is closed?

There is currently no reliable option on how to update BackgroundDonwloader progress in Toast notification through Progress<DownloadOperation>.
As per Microsoft documentation, BackgroundTask could be suspended or killed based on the actual system state. That could happen before the BackgroundDownloader finishes its job and your Toast notification will look like it got frozen.
The best approach here is to update your Toast progress bar in the app suspended or exited event with AdaptiveProgressBarValue.Indeterminate with appropriate texting (e.g. Finishing download in background, etc.). Based on comments from #Faywang - MSFT you can still get notifications about successful or failed download even the app is closed or suspended.
Another approach would be to use extendedExecutionUnconstrained to be able to run BackgroundTask indefinitely. In that case, you would be able to update Toast progress with 'live' data and even more, to trigger new download via BackgroundDownloader. The downside of this approach is that your app cannot be listed in Microsoft Store.

Related

Windows Store Api Package Update

I was trying to update the UWP app(which is in store with higher version) through programmatically. But the problem is after downloading and installation process, as per MS docs not getting any OS popup that application is going to restart.
On completion, it just restart the app, also not reaching to "Completed" state.
Also In between Internet pause and restart automatically update the system, not providing control to developer.
Any Idea how to do that.
Doc link - https://learn.microsoft.com/en-us/windows/uwp/packaging/self-install-package-updates
AsyncOperationWithProgress<StorePackageUpdateResult, StorePackageUpdateStatus> downloadOperation1 =
updateManager.RequestDownloadAndInstallStorePackageUpdatesAsync(updates);
downloadOperation1.Progress = async (asyncInfo, progress) =>
{
await Task.Run(() =>
{
this.ProgressUpdateValue = progress.PackageDownloadProgress;
}).ConfigureAwait(true);
};
StorePackageUpdateResult downloadResult1 = await downloadOperation1.AsTask().ConfigureAwait(true);
switch (downloadResult1.OverallState)
```

Getting SpeechRecognizer to correctly utilize timeouts for EndSilenceTimeout

I'm trying to re-purpose a code-snippet for a UWP app using Windows.Media.SpeechRecognition's SpeechRecognizer class.
The problem is that it doesn't seem to utilize the timeout that I set for EndSilenceTimeout -- yet both BabbleTimeout and InitialSilenceTimeout appear to be working just fine. Basically, a 1-2 second pause will always end the session, and I'm trying to figure out how to fix or work around this.
I've tried with both RecognizeAsync and RecognizeWithUIAsync but neither made a difference.
private async void StartRecognizing()
{
var speechRecognizer = new SpeechRecognizer();
speechRecognizer.Timeouts.EndSilenceTimeout = TimeSpan.FromSeconds(10);
speechRecognizer.Timeouts.BabbleTimeout = TimeSpan.FromSeconds(10);
speechRecognizer.Timeouts.InitialSilenceTimeout = TimeSpan.FromSeconds(10);
await speechRecognizer.CompileConstraintsAsync();
SpeechRecognitionResult speechRecognitionResult = await speechRecognizer.RecognizeAsync();
var messageDialog = new Windows.UI.Popups.MessageDialog(speechRecognitionResult.Text, "Text spoken");
await messageDialog.ShowAsync();
}
To test this, just make a new UWP app in Visual Studio and grant yourself permission to access the microphone in the package app manifest; additionally you'll need to make sure your OS itself allows for this in the Speech, inking, & typing settings on Windows 10 v1803.

Windows Phone 8.1 Background Agent invokes a custom method severally

I have a background agent for my windows phone 8.1(C#) which listens to push notifications.
I also have a foreground App and it handles push notification if it is running.
The problem is that the background agent invokes a custom method await SyncPushChanges.initUpdate(true); several times causing duplicate values in my sqlite database.
Here is code for foreground delegate:
static async void channel_PushNotificationReceived(PushNotificationChannel sender, PushNotificationReceivedEventArgs args)
{
//Init update from the server
await SyncPushChanges.initUpdate();
//Prevent background agentt from being invoked
args.Cancel = true;
}
Code In background Agent
public async void Run(IBackgroundTaskInstance taskInstance)
{
var deferal = taskInstance.GetDeferral();//Save on CPU seconds since we are doing async
//Get the token and invoke get new data
await SyncPushChanges.initUpdate(true);
deferal.Complete();
}
Anyone who might know why am having my method invokes many times?Your help will be highly appreciated
I found a solution myself.
The issue was that I was not unregistering my background agent and this caused it to work incorrectly when the app was updated(In this case when I run the application again from VS2013).
The following code did the magic
BackgroundExecutionManager.RemoveAccess();
//Unregister the Background Agent
var entry = BackgroundTaskRegistration.AllTasks.FirstOrDefault(keyval => keyval.Value.Name == "myAgent");
if (entry.Value != null)
{
entry.Value.Unregister(true);
}

Windows Phone 8.1 Background Tasking is not stopping?

I have designed a music player for windows phone 8.1. When i clicked the play button foreground app sends the messsage to background audio class. background audio class plays my music. All is ok. But i have a problem. When i close my app (pressin back button and slide down) back ground music is still playing. How i can close it ? thanks.
public void Run(IBackgroundTaskInstance taskInstance)
{
Debug.WriteLine("Background Audio Task " + taskInstance.Task.Name + " starting...");
// Initialize SMTC object to talk with UVC.
//Note that, this is intended to run after app is paused and
//hence all the logic must be written to run in background process
systemmediatransportcontrol = SystemMediaTransportControls.GetForCurrentView();
systemmediatransportcontrol.ButtonPressed += systemmediatransportcontrol_ButtonPressed;
systemmediatransportcontrol.PropertyChanged += systemmediatransportcontrol_PropertyChanged;
systemmediatransportcontrol.IsEnabled = true;
systemmediatransportcontrol.IsPauseEnabled = true;
systemmediatransportcontrol.IsPlayEnabled = true;
systemmediatransportcontrol.IsNextEnabled = true;
systemmediatransportcontrol.IsPreviousEnabled = true;
// Associate a cancellation and completed handlers with the background task.
taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled);
taskInstance.Task.Completed += Taskcompleted;
var value = ApplicationSettingsHelper.ReadResetSettingsValue(Constants.AppState);
if (value == null)
foregroundAppState = ForegroundAppStatus.Unknown;
else
foregroundAppState = (ForegroundAppStatus)Enum.Parse(typeof(ForegroundAppStatus), value.ToString());
//Add handlers for MediaPlayer
BackgroundMediaPlayer.Current.CurrentStateChanged += Current_CurrentStateChanged;
//Add handlers for playlist trackchanged
Playlist.TrackChanged += playList_TrackChanged;
//Initialize message channel
BackgroundMediaPlayer.MessageReceivedFromForeground += BackgroundMediaPlayer_MessageReceivedFromForeground;
//Send information to foreground that background task has been started if app is active
if (foregroundAppState != ForegroundAppStatus.Suspended)
{
ValueSet message = new ValueSet();
message.Add(Constants.BackgroundTaskStarted, "");
BackgroundMediaPlayer.SendMessageToForeground(message);
}
BackgroundTaskStarted.Set();
backgroundtaskrunning = true;
ApplicationSettingsHelper.SaveSettingsValue(Constants.BackgroundTaskState, Constants.BackgroundTaskRunning);
deferral = taskInstance.GetDeferral();
}
This article describes the application lifecycle of a Windows Store App.
If you look at the very first figure, you can see that there are only 3 events related to application lifecycle:
Activated - Raised when program first starts
Suspended - Raised when program is suspended (i.e. the user returns to the Start Screen or another app)
Resuming - Raised when the program is awakened from its suspended state.
The fourth transition - the one to the "Not Running" state - has no such notification event. The reason is: you don't really know when the app will fully close. Nor should you - Microsoft wants you to perform all of your state-saving logic in the transition from "Running" to "Suspended." In this way, they can free up resources when they deem necessary.
Even if the user forces the program to terminate (by right-clicking it and selecting "Close" from the task menu), you will enter the "Suspended" state for exactly 10 seconds before the program is terminated. So you can rest easy that your state-saving logic will always be executed.
So, You can close music in App Suspending event or state saving event.

Background downloader windows 8 Multiple files

I'm having some files that I need to download on app startup (first run).
I am using the Background Downloader in windows 8.
This is how I use it:
BackgroundDownloader downloader = new BackgroundDownloader();
List<DownloadOperation> operations = new List<DownloadOperation>();
foreach (FileInfo info in infoFiles)
{
Windows.Storage.ApplicationData.Current.LocalFolder;
foreach (string folder in info.Folders)
{
currentFolder = await currentFolder.CreateFolderAsync(folder, CreationCollisionOption.OpenIfExists);
}
//folder hierarchy created, save the file
StorageFile file = await currentFolder.CreateFileAsync(info.FileName, CreationCollisionOption.ReplaceExisting);
DownloadOperation op = downloader.CreateDownload(new Uri(info.Url), file);
activeDownloads.Add(op);
operations.Add(op);
}
foreach (DownloadOperation download in operations)
{
//start downloads
await HandleDownloadAsync(download, true);
}
When I try to use BackgroundDownloader.GetCurrentDownloadsAsync(); I get only one background download discovered. So I removed the await operator above to get them to start asynchronously.
However I need to know when all files are finished so I can set a progress bar.
I need a way to download multiple files, discover all of them in BackgroundDownloader.GetCurrentDownloadsAsync(); and know when all downloads are completed.
private async Task HandleDownloadAsync(DownloadOperation download, bool start)
{
try
{
Debug.WriteLine("Running: " + download.Guid, NotifyType.StatusMessage);
// Store the download so we can pause/resume.
activeDownloads.Add(download);
Progress<DownloadOperation> progressCallback = new Progress<DownloadOperation>(DownloadProgress);
if (start)
{
// Start the download and attach a progress handler.
await download.StartAsync().AsTask(cts.Token, progressCallback);
}
else
{
// The download was already running when the application started, re-attach the progress handler.
await download.AttachAsync().AsTask(cts.Token, progressCallback);
}
ResponseInformation response = download.GetResponseInformation();
Debug.WriteLine(String.Format("Completed: {0}, Status Code: {1}", download.Guid, response.StatusCode),
NotifyType.StatusMessage);
}
catch (TaskCanceledException)
{
Debug.WriteLine("Canceled: " + download.Guid, NotifyType.StatusMessage);
}
catch (Exception ex)
{
if (!IsExceptionHandled("Execution error", ex, download))
{
throw;
}
}
finally
{
activeDownloads.Remove(download);
}
}
If you specifically need to re-download the file at every app startup, you shouldn't use BackgroundDownloader - it's intended for scenarios where you need downloads that keep on happening even when your app gets suspended and then restarted. If you're just going to re-download the files again when your app starts up again next time, you're just wasting battery by allowing the downloads to continue once your app goes away.
You have a few options for non-background-capable downloads in a Windows Store app. The most straightforward is Windows.Web.Http.HttpClient - here's a good primer on how to use it. However, it's only available in Windows 8.1 apps, not Windows 8.0. If you need Windows 8.0 compatibility, the distinct but similarly named System.Net.Http.HttpClient is probably the way to go. Harrison already provided a link to the relevant Quickstart documentation.
If you really do want background download capability, please revise your question to more accurately reflect your scenario. It's certainly possible to use BackgroundDownloader to start up several background downloads concurrently and attach progress and completion handlers to each of them, but that doesn't sound like the best solution for the scenario in your question.
Now that you've clarified your usage, the issue is more clear. Your HandleDownloadAsync method is attaching the progress handler you want to the download, but then it's awaiting the completion of that download. When you write
foreach (DownloadOperation download in operations)
{
//start downloads
await HandleDownloadAsync(download, true);
}
you are therefore awaiting on the completion of each download in turn before you start the next download.
The solution here is to not await the result of your HandleDownloadAsync calls until after you've performed all of the calls - this will start up each of the downloads immediately and attach the appropriate progress handlers without waiting for any of them to complete. A revised version might look something like this:
BackgroundDownloader downloader = new BackgroundDownloader();
List<Task> downloadCompletionTasks = new List<Task>();
foreach (FileInfo info in infoFiles)
{
StorageFile file = /* ... */;
DownloadOperation op = downloader.CreateDownload(new Uri(info.Url), file);
// Consider moving this line into HandleDownloadAsync so you won't have to repeat
// it in the code that's handling the GetCurrentDownloadsAsync logic.
activeDownloads.Add(op);
// Starting the download, but not awaiting its completion yet
Task downloadCompletionTask = HandleDownloadAsync(op, true);
downloadCompletionTasks.Add(downloadCompletionTask);
}
// Now that we've got all the downloads started concurrently, we can wait until all of them complete
await Task.WhenAll(downloadCompletionTasks);

Categories