Update:
After doing a lot more debugging, I figured out the cause of my notification not updating: Calling setProgress(0, 0, false)
upon completion of the download. For some reason when this method is called before notify()
, the upcoming update doesn't actually go through. Adding a NotificationChannel doesn't do anything.
My current workaround is to call setProgress(100, 100, false)
so that the user can tell the download is finished and will subsequently get updated.
Original question:
I've got a custom file downloading utility that creates a notification whenever a file is being downloaded. This notification gets updated as the download progresses. However, I am getting some odd results on API levels above 19. When the download is finished, the NotificationManager doesn't update the notification to inform the user of this. The notification does get updated whenever the download progresses, strangely enough. Also, when I have the debugger active, the notification does get updated when the download completes. This leads me to believe some sort of race condition is happening here but I can't really seem to find out where or how.
My FileDownloader class:
public static void startGetRequestDownload(final Context context,
String fileUrl,
@Nullable String fileName,
@Nullable Header[] headers,
@Nullable RequestParams requestParams,
final boolean showProgressNotification){
final int notificationID = 0;
final NotificationManager mNotifyManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if(mNotifyManager == null) {
Log.e(TAG, "Failed to get NotificationManager service");
return;
}
final NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context);
String notificationTitle = context.getString(R.string.default_filename);
if(fileName != null && !fileName.isEmpty()){
notificationTitle = fileName;
}
mBuilder.setContentTitle(notificationTitle)
.setContentText(context.getString(R.string.download_in_progress))
.setColor(ContextCompat.getColor(context, R.color.app_color_accent))
.setSmallIcon(R.drawable.ic_elab);
String uuid = "Temp_" + System.currentTimeMillis();
final File tempFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString(), uuid);
// Temporarily disable SSL as workaround.
RestClient.getClient().setSSLSocketFactory(MySSLSocketFactory.getFixedSocketFactory());
RestClient.getClient().get(context, fileUrl, headers, requestParams, new FileAsyncHttpResponseHandler(tempFile) {
@Override
public void onStart() {
super.onStart();
if(showProgressNotification){
mBuilder.setProgress(100, 0, false);
mNotifyManager.notify(notificationID, mBuilder.build());
}
}
@Override
public void onProgress(long bytesWritten, long totalSize) {
super.onProgress(bytesWritten, totalSize);
if(showProgressNotification){
int progress = (int) (bytesWritten / totalSize * 100);
mBuilder.setProgress(100, progress, false);
mNotifyManager.notify(notificationID, mBuilder.build());
}
}
@Override
public void onFailure(int statusCode, Header[] headers, Throwable throwable, File file) {
if(showProgressNotification){
mBuilder.setContentText(context.getString(R.string.download_failed));
mBuilder.setProgress(0,0,false);
mNotifyManager.notify(notificationID, mBuilder.build());
}
Log.w(TAG, "File download failed", throwable);
}
@Override
public void onSuccess(int statusCode, Header[] headers, File file) {
FileMetaData metaData = validateResponse(headers);
if(metaData != null){
final File downloadDirectory = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString());
File newFile = new File(downloadDirectory, metaData.fileName);
if(file.renameTo(newFile)){
Uri fileUri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".fileprovider", newFile);
Intent actionViewIntent = new Intent(Intent.ACTION_VIEW);
actionViewIntent.setDataAndType(fileUri, metaData.contentType);
actionViewIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if(showProgressNotification){
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, actionViewIntent, PendingIntent.FLAG_ONE_SHOT);
mBuilder.setProgress(0,0,false);
mBuilder.setContentText(context.getString(R.string.download_completed));
mBuilder.setContentIntent(pendingIntent);
mBuilder.setSmallIcon(android.R.drawable.stat_sys_download_done);
mNotifyManager.notify(notificationID, mBuilder.build());
}
return;
}
}
//Failover
if(showProgressNotification){
mBuilder.setContentText(context.getString(R.string.download_failed));
mNotifyManager.notify(notificationID, mBuilder.build());
}
}
});
}
I figured out the actual reason as to why my notification wasn't getting updated. The Android documentation mentions the following in regards to notification updates:
Caution: The system applies a rate limit to updating notifications. If you post updates to a notification too frequently, the system may drop some notifications.
I was calling notify()
every time the download progressed. Obviously, the download progress method was called very often, which resulted in several notifications getting blocked. However, I only saw the last notification getting dropped: The download completion notification.
Limiting the amount of calls to notify()
in onProgress()
fixed my issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With