Workmanager doesn't work in standby and doze mode - android

I'm using WorkManager that schedule my notifications, it works when my smartphone is active, but it doesn't work when my smartphone is in standby. Why? There is some constraint that let me that? Or whatever?
Method notifyPush in CoreActivity.java
public static void notifyPush(String message, Context context)
{
//codice di un altro programma
// Make a channel if necessary
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
CharSequence name = Constants.VERBOSE_NOTIFICATION_CHANNEL_NAME;
String description = Constants.VERBOSE_NOTIFICATION_CHANNEL_DESCRIPTION;
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
// Add the channel
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
notificationManager.createNotificationChannel(channel);
}
}
// Create the notification
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle(Constants.NOTIFICATION_TITLE)
.setContentText(message)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setDefaults(DEFAULT_ALL);
//.setVibrate(new long[0]);
// Show the notification
NotificationManagerCompat.from(context).notify(Constants.NOTIFICATION_ID, builder.build());
}
NotifyWorker.java
package com.example.msnma.movienotifier.notify;
import android.content.Context;
import android.support.annotation.NonNull;
import android.util.Log;
import com.example.msnma.movienotifier.CoreActivity;
import androidx.work.Data;
import androidx.work.Worker;
import static com.example.msnma.movienotifier.CoreActivity.notifyPush;
import static com.example.msnma.movienotifier.notify.Constants.KEY_MOVIE;
public class NotifyWorker extends Worker {
//private static final String TAG = BlurWorker.class.getSimpleName();
#NonNull
#Override
public Worker.Result doWork() {
Context applicationContext = getApplicationContext();
String message = getInputData().getString(Constants.KEY_MOVIE);
//setOutputData(new Data.Builder().putString(
//KEY_MOVIE, message.toString()).build());
try {
notifyPush(message , applicationContext);
return Worker.Result.SUCCESS;
} catch (Throwable throwable) {
// Technically WorkManager will return WorkerResult.FAILURE
// but it's best to be explicit about it.
// Thus if there were errors, we're return FAILURE
Log.e("NotifyWorker", "Error notification", throwable);
return Worker.Result.FAILURE;
}
}
}
Methods scheduleNotify and deleteNotify in MovieAdapter.java
private UUID scheduleNotify(Date d, int position)
{
long currentTime= System.currentTimeMillis();
//Calendar c = new Date;
long specificTimeToTrigger = d.getTime();
//d.getTimeToMillis();
long delayToPass = specificTimeToTrigger - currentTime;
/*OneTimeWorkRequest compressionWork =
new OneTimeWorkRequest.Builder(NotifyWorker.class)
.setInputData(message)
.setInitialDelay(delayToPass, TimeUnit.MILLISECONDS)
.build();*/
//inizialmente รจ molto semplice la notifica
OneTimeWorkRequest notifyRequest =
new OneTimeWorkRequest.Builder(NotifyWorker.class)
.setInputData(createInputDataForUri(movies.get(position)))
.setInitialDelay(delayToPass,TimeUnit.MILLISECONDS)
.build();
mWorkManager.enqueue(notifyRequest);
UUID notify_ID = notifyRequest.getId();
//WorkManager.getInstance().enqueue(compressionWork);
return notify_ID;
}
public void deleteNotify(UUID notify_ID)
{
WorkManager.getInstance().cancelWorkById(notify_ID);
}

WorkManager uses JobScheduler and that will batch jobs during maintenance windows to optimize battery usage.
Also, here is the constraint you are looking for.

Since Version 1.0.0-alpha06
A bug which causes PeriodicWork to not run on schedule when in Doze mode was fixed .
https://issuetracker.google.com/issues/111469837

Related

Can't get Notification to pop up on Oreo (Android 8.0) and higher. What exactly am I doing wrong?

I tried almost every answer I saw on StackOverflow and CodinginFlow.com but even after everything. My code doesn't still work. Months ago I saw a developer warning; in form of a Toast, that I can't post notifications to the channel, and after searching and searching StackOverflow yesterday, I still haven't gotten it to work. But the Toast message doesn't pop up. I don't know what I missed. Didn't I do it right?
Code below...
AndroidManifest.xml
...
<application
android:allowBackup="true"
android:name=".main.App"
android:fullBackupContent="true"
android:icon="#mipmap/timely_app_icon"
android:label="#string/app_name"
android:requestLegacyExternalStorage="true"
android:roundIcon="#mipmap/timely_app_icon_round"
android:theme="#style/AppTheme">
...
App.java
package com.noah.timely.main;
import android.app.Application;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
import androidx.annotation.RequiresApi;
import androidx.core.content.ContextCompat;
import com.noah.timely.R;
public class App extends Application {
public static final String ASSIGNMENT_CHANNEL = "TimeLY's assignments";
public static final String ASIGNMENT_CHANNEL_ID = "com.noah.timely.assignments";
public static final String ALARMS_CHANNEL = "TimeLY's study alarm";
public static final String ALARMS_CHANNEL_ID = "com.noah.timely.alarms";
public static final String SCHEDULED_TIMETABLE_CHANNEL = "TimeLY's Scheduled Classes";
public static final String SCHEDULED_TIMETABLE_CHANNEL_ID = "com.noah.timely.scheduled";
public static final String TIMETABLE_CHANNEL = "TimeLY's Timetable";
public static final String TIMETABLE_CHANNEL_ID = "com.noah.timely.timetable";
public static final String GENERAL_CHANNEL = "Miscellaneous";
public static final String GENERAL_CHANNEL_ID = "com.noah.timely";
#Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannels();
}
}
#RequiresApi(api = Build.VERSION_CODES.O)
private void createNotificationChannels() {
NotificationManager mgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel1 = new NotificationChannel(ASIGNMENT_CHANNEL_ID, ASSIGNMENT_CHANNEL,
NotificationManager.IMPORTANCE_DEFAULT);
channel1.setLightColor(ContextCompat.getColor(this, android.R.color.holo_purple));
mgr.createNotificationChannel(channel1);
NotificationChannel channel2 = new NotificationChannel(ALARMS_CHANNEL_ID, ALARMS_CHANNEL,
NotificationManager.IMPORTANCE_HIGH);
channel1.setLightColor(ContextCompat.getColor(this, android.R.color.holo_orange_light));
mgr.createNotificationChannel(channel2);
NotificationChannel channel3 = new NotificationChannel(SCHEDULED_TIMETABLE_CHANNEL_ID, SCHEDULED_TIMETABLE_CHANNEL,
NotificationManager.IMPORTANCE_DEFAULT);
channel1.setLightColor(ContextCompat.getColor(this, android.R.color.holo_green_light));
mgr.createNotificationChannel(channel3);
NotificationChannel channel4 = new NotificationChannel(TIMETABLE_CHANNEL_ID, TIMETABLE_CHANNEL,
NotificationManager.IMPORTANCE_DEFAULT);
channel1.setLightColor(ContextCompat.getColor(this, android.R.color.holo_red_light));
mgr.createNotificationChannel(channel4);
NotificationChannel channel5 = new NotificationChannel(GENERAL_CHANNEL_ID, GENERAL_CHANNEL,
NotificationManager.IMPORTANCE_DEFAULT);
channel5.setDescription(getString(R.string.miscellaneous_channel_desc));
mgr.createNotificationChannel(channel5);
}
}
And this was how I posted the notification. The code was executed inside a BroadcastReceiver
NotificationManagerCompat manager = NotificationManagerCompat.from(context);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, App.ALARMS_CHANNEL_ID);
builder.setContentTitle("Alarm for: " + (is24 ? _24H : _12H) + (isSnoozeAction ? " (Snoozed)" : ""))
.setContentText(alarmLabel)
.setSmallIcon(R.drawable.ic_n_alarm)
.setColor(ContextCompat.getColor(context, R.color.colorPrimaryDark))
.setContentIntent(pi)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setSilent(true)
.setFullScreenIntent(pi, true)
.addAction(new NotificationCompat.Action(R.drawable.ic_n_snooze, "Snooze", actionSnooze))
.addAction(new NotificationCompat.Action(R.drawable.ic_n_cancel, "Dismiss", actionDismiss));
manager.notify(NOTIFICATION_ID, builder.build());
The code above should have displayed a heads-up notification, but only post regular notification. The code below doesn't even post a notification.
NotificationManagerCompat manager = NotificationManagerCompat.from(context);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, App.SCHEDULED_TIMETABLE_CHANNEL_ID);
builder.setStyle(new NotificationCompat.BigTextStyle().bigText(spannedMessage))
.setContentTitle("Scheduled class reminder")
.setContentText(spannedMessage)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setSmallIcon(R.drawable.ic_n_schedule)
.setColor(ContextCompat.getColor(context, R.color.colorPrimaryDark))
.setSound(DEFAULT_URI)
.setContentIntent(pi);
manager.notify(-299, builder.build());

Android Work Manager is not working in my oppo phone

I wrote this program to sync data with the server. Before checking it with the server. I wrote a program to send notifications every 15 minutes.
My phone is oppo A71
Android version 7.1
The following code is not working when I closed the app.
MainActivity.java
PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(
MyPeriodicWork.class,15, TimeUnit.MINUTES)
.addTag("send data") .build();
WorkManager.getInstance().enqueue(periodicWorkRequest);
MyPeriodicWork.java
public class MyPeriodicWork extends Worker {
private static final String FILE_NAME = "chata.txt";
private static final String TAG = "MyPeriodicWork";
public MyPeriodicWork(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
#NonNull
#Override
public Result doWork() {
showNotif();
Log.e(TAG,"doWork:work is done");
return Result.success();
}
public void showNotif(){
Intent intent = new Intent(getApplicationContext(),MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),0,intent,0);
Calendar calendar = Calendar.getInstance();
SimpleDateFormat mdformat = new SimpleDateFormat("HH:mm:ss");
String strDate = "Current Time : " + mdformat.format(calendar.getTime());
NotificationCompat.Builder notificationCompat = new NotificationCompat.Builder(getApplicationContext(),"14")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Event Handler")
.setContentText("Helloo"+strDate)
.setContentIntent(pendingIntent)
.setAutoCancel(true);
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(getApplicationContext());
notificationManagerCompat.notify(4,notificationCompat.build());
}
}
Do I need to add some permissions to manifest file. If yes what are those codes.
this problem on Chinese custom rom they have blacklisted all app except some big app like Facebook,whatsapp etc etc

NotificationChannel sound needs restart phone

I am trying to provide local notification into my App with my custom sound.
I created simple app in Visual Studio, and I want show notification on FAB Click.
My problem is that, notification is displaying, but without sound.
But... After phone restart - notification works properly with sound!
My code - create channel method called in OnCreate():
string channelId = "1";
string channelName = "a";
int notificationId = 0;
private void createNotificationChannel()
{
var notMgr = (NotificationManager)GetSystemService(NotificationService);
var uri = new Android.Net.Uri.Builder()
.Scheme(ContentResolver.SchemeAndroidResource)
.Authority(Resources.GetResourcePackageName(Resource.Raw.neworder4))
.AppendPath(Resources.GetResourceTypeName(Resource.Raw.neworder4))
.AppendPath(Resources.GetResourceEntryName(Resource.Raw.neworder4))
.Build();
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
if (notMgr.GetNotificationChannel(channelId) == null)
{
var channel = new NotificationChannel(channelId, channelName, NotificationImportance.Default);
channel.Description = channelName;
var aa = new AudioAttributes.Builder()
.SetContentType(AudioContentType.Sonification)
.SetUsage(AudioUsageKind.Notification).Build();
channel.SetSound(uri, aa);
notMgr.CreateNotificationChannel(channel);
}
}
}
Show notification on FAB click:
private void FabOnClick(object sender, EventArgs eventArgs)
{
var notMgr = (NotificationManager)GetSystemService(NotificationService);
notificationId = notificationId + 1;
var not = new NotificationCompat.Builder(this, channelId)
.SetSmallIcon(Resource.Mipmap.ic_launcher)
.SetContentText("test")
.SetContentTitle("test")
.Build();
notMgr.Notify(notificationId, not);
}
What I'm doing wrong?
I don't want to require my users to reboot phones after app install.
Resource.Raw.neworder4 is mp3 file, and is set as Android Resource.
I use the following code to play custom sound for Local Notification, it works fine, you can take a look:
Creating channel:
string channelId = "location_notification";
string channelName = "localnotification";
int notificationId = 1000;
void CreateNotificationChannel()
{
if (Build.VERSION.SdkInt < BuildVersionCodes.O)
{
// Notification channels are new in API 26 (and not a part of the
// support library). There is no need to create a notification
// channel on older versions of Android.
return;
}
Android.Net.Uri sound = Android.Net.Uri.Parse("android.resource://" + Application.Context.PackageName + "/" + Resource.Raw.MyAudio);
var aa = new AudioAttributes.Builder()
.SetContentType(AudioContentType.Sonification)
.SetUsage(AudioUsageKind.Notification).Build();
var channelDescription = "local notification!!!!";
var channel = new NotificationChannel(channelId, channelName, NotificationImportance.Max)
{
Description = channelDescription
};
channel.SetSound(sound,aa);
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.CreateNotificationChannel(channel);
}
Building the notification:
private void Button3_Click(object sender, System.EventArgs e)
{
// Build the notification:
var builder = new NotificationCompat.Builder(this, channelId)
.SetAutoCancel(true) // Dismiss the notification from the notification area when the user clicks on it
.SetDefaults((int)NotificationDefaults.All)
.SetContentTitle("Button Clicked") // Set the title
//.SetSound(RingtoneManager.GetDefaultUri(RingtoneType.Alarm))
.SetSmallIcon(Resource.Drawable.addreminder); // This is the icon to display
// Finally, publish the notification:
var notificationManager = NotificationManagerCompat.From(this);
notificationManager.Notify(notificationId, builder.Build());
}
I found solution for one part of my problem (for Emulator):
https://stackoverflow.com/a/56935747
I tested notifications on physical phone with android 9.0, and there is no sound for notifications without restart phone.
For now I think provided solution is close enough for me.

ListenableWorker done, but ongoing foreground notification still exists?

I am trying to use ListenableWorker to perform some background API calls.
During this process I want to display notification with a progress.
I use setForegroundAsync() function as per this documentation google docs
The problem is when my ListenableWorker stops, i can still see my ongong notification and i cant remove it.
This is my refresh fucntion where I change notification parameters:
private void updateRefreshStatus(float objectsProcessed, int totalObjects) {
if (totalObjects == 0) {
setProgressAsync(new Data.Builder().putFloat(PROGRESS_CONSTANT_ID, 100.0f).build());
setForegroundAsync(createForegroundInfo(FloatFormatter.roundFloatTwoDigitsAsString(100f)));
} else {
setProgressAsync(new Data.Builder().putFloat(PROGRESS_CONSTANT_ID, (objectsProcessed / (float) totalObjects) * 100f).build());
setForegroundAsync(createForegroundInfo(FloatFormatter.roundFloatTwoDigitsAsString((objectsProcessed / (float) totalObjects) * 100f)));
}
}
This is how I create my foregroundInfo:
private ForegroundInfo createForegroundInfo(#NonNull String progress) {
Notification notification = WorkerUtils.prepareProgressNotification("Update",
"Update progress " + progress + " %",
getApplicationContext());
return new ForegroundInfo(NOTIFICATION_PROGRESS_ID,notification);
}
This is my progress notification code:
static Notification prepareProgressNotification(String title, String message, Context context) {
// Make a channel if necessary
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
CharSequence name = WorkerConstants.VERBOSE_NOTIFICATION_CHANNEL_NAME;
String description = WorkerConstants.VERBOSE_NOTIFICATION_CHANNEL_DESCRIPTION;
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel =
new NotificationChannel(WorkerConstants.CHANNEL_ID, name, importance);
channel.setDescription(description);
// Add the channel
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
notificationManager.createNotificationChannel(channel);
}
}
// Create the notification
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, WorkerConstants.CHANNEL_ID)
.setContentTitle(title)
.setSmallIcon(R.drawable.ic_launcher)
.setContentText(message)
.setTicker(title)
.setOngoing(true)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setVibrate(new long[0]);
// Show the notification
return builder.build();
}
I tried calling cancelAll, cancel(id), but it does nothing in my case.
UPDATE: Removing .setOngoing(true) from builder, does nothing for me its seems like setForegroundAsync() issue?

Notification does not show immediately even provided by a unique id

I check it many times using Logs and prevent the notify() method of manager to be called multiple times if not necessary to avoid some overhead. Now I have first notification with a 0% progress then again I create a new notification with a 0% progress again, unfortunately only one notification is shown even their id is unique but later on when the first notification progress gets updated example from 0% to 25% then that's the only time it will show the desired output, a 2 notification with different progress value. I am using only one Notification, Notification Manager, and in Notification Builder since I do not want to create an overlap animation of notification when it gets updated. Is this expected behavior when in the foreground?
public abstract class BaseTaskService extends Service {
private static final String TAG = "BaseTaskService";
private static final String CHANNEL_ID_DEFAULT = "Upload and Download";
private int queue = 0;
private FirebaseFirestore mDatabase;
private final List<Integer> listOfTaskID = new ArrayList<>();
private final SparseIntArray totalUnitList = new SparseIntArray();
private final SparseIntArray completedUnitList = new SparseIntArray();
private Notification notification;
private NotificationManager notificationManager;
private final NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID_DEFAULT);
public void taskStarted(int id, boolean isUpload) {
//Increase the number of task
changeNumberOfTasks(1);
//Check if the task is new or not, if new then start a foreground service using id for it and add it to the list
if (!listOfTaskID.contains(id)){
listOfTaskID.add(id);
startForeground(id, notification);
Log.d(TAG, "Foreground Task Created : ID = " + id);
}
//If called by Upload Service, start the service once as a foreground per post
//If called by Download Service, start the service once as a foreground per file
if (isUpload){
//Set a total unit of files per post since one post could incorporate numerous images or files
totalUnitList.append(id, totalUnitList.get(id, 0) + 1);
Log.d(TAG, "Total Units For " + id + ": (" + totalUnitList.get(id) + ")");
}
}
public void taskCompleted() {
changeNumberOfTasks(-1);
}
private synchronized void changeNumberOfTasks(int delta) {
//Update the queue by adding delta value which could be 1 or -1
//Queue will display the overall upload or download of file from different tasks
queue += delta;
Log.d(TAG, "Overall Number of Remaining Task: " + queue);
//If there are no tasks left in queue, stop the service :)
if (queue <= 0) {
Log.d(TAG, "Stopping...");
//In Upload Service if there is no task in our queue it means that all request was finished
//so we need to reset the list of post's total task and completed task to zero
totalUnitList.clear();
completedUnitList.clear();
//Clear all of the id task
listOfTaskID.clear();
//Stop the foreground and remove all notification
stopForeground(true);
//Stop this service, calling this method will dismiss the very recent notification.
stopSelf();
}
}
#Override
public void onCreate() {
super.onCreate();
mDatabase = FirebaseFirestore.getInstance();
if (!isNotificationChannelEnabled(CHANNEL_ID_DEFAULT))
Toast.makeText(this, "Please turn on the notification in the app settings.", Toast.LENGTH_SHORT).show();
}
/*
We could use this line but unfortunately it will no longer work on Android O and above so we'll use the hashcode below.
This line is suppose to use for separating/detaching the Foreground notification from a Service
so that generating a separated unique id for PendingIntent and Finished notification is no longer needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
stopForeground(STOP_FOREGROUND_DETACH);
else
ServiceCompat.stopForeground(this, STOP_FOREGROUND_DETACH);
*/
//For Android O and above
private void createDefaultChannel() {
// Since Android Oreo notification channel is needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//If null then initialize the Notification Manager
if (notificationManager == null)
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel = new NotificationChannel(CHANNEL_ID_DEFAULT,
"Upload and Download",
NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
}
public boolean isNotificationChannelEnabled(String channelId){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if(channelId != null) {
NotificationManager manager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel = manager.getNotificationChannel(channelId);
return channel.getImportance() != NotificationManager.IMPORTANCE_NONE;
}
return false;
} else {
return NotificationManagerCompat.from(this).areNotificationsEnabled();
}
}
/**
* Show notification with a progress bar.
* Updating the progress happens here
* This is for DOWNLOAD SERVICE
*/
void showProgressNotification(String caption, long completedUnits, long totalUnits, int id) {
createDefaultChannel();
//If null then initialize the Notification Manager
if (notificationManager == null)
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
//Compute the progress
int percentComplete = 0;
if (totalUnits > 0) {
percentComplete = (int) (100 * completedUnits / totalUnits);
}
//To update and separate the notification progress according to its task
notification = notificationBuilder
.setProgress(100, percentComplete, false)
.setContentInfo(String.valueOf(percentComplete +"%"))
.setSmallIcon(R.drawable.ic_file_upload_white_24dp)
.setContentTitle(getString(R.string.app_name))
.setContentText(caption)
.setAutoCancel(false)
.setOngoing(true)
.build();
if (!listOfTaskID.contains(id))
Log.d(TAG, "Download Notification Created: ID = " + id);
else
Log.d(TAG, "Download Notification Updated: ID = " + id);
//Notify the manager that we have a new update with notification
notificationManager.notify(id, notification);
}
/**
* Show notification with a progress bar.
* Updating the progress happens here
* This is for UPLOAD SERVICE
*/
void showProgressNotification(String caption, final String path, final int id, boolean isComplete, String title, String desc) {
createDefaultChannel();
//If null then initialize the Notification Manager
if (notificationManager == null)
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
//Increment only if it is a successful task
if (isComplete)
completedUnitList.append(id, completedUnitList.get(id,0) + 1);
//Update and compute the progress
double percentComplete = 0;
if (totalUnitList.get(id, 0) > 0) {
//Perform this line if and only the total task is not equal to zero since dividing a number by zero is Error
percentComplete = (100 / totalUnitList.get(id)) * completedUnitList.get(id, 0);
}
notification = notificationBuilder
.setProgress(100, (int) percentComplete, false)
.setContentInfo(String.valueOf((int) percentComplete +"%"))
.setSmallIcon(R.drawable.ic_file_upload_white_24dp)
.setContentTitle(getString(R.string.app_name))
.setContentText(caption)
.setAutoCancel(false)
.setOngoing(true)
.build();
//This if condition is use to avoid repetitive call of notify() and will be triggered only if new task is created
if (!isComplete && !listOfTaskID.contains(id)){
Log.d(TAG, "Upload Notification Created: ID = " + id);
//Notify the manager that we have a new notification
notificationManager.notify(id, notification);
}
else if (isComplete){
Log.d(TAG, "Upload Notification Updated: ID = " + id);
//Notify the manager that we have a new update with notification
notificationManager.notify(id, notification);
//Check now if the number of completed task is equal to the number of total task if yes then show a finish notification
if (completedUnitList.get(id) == totalUnitList.get(id)){
Map<String, Object> details = new HashMap<>();
details.put(getResources().getString(R.string.Description), desc);
//We will use milliseconds to calculate how long is the post and for query
details.put(getResources().getString(R.string.Time_Posted), String.valueOf(new Date().getTime()));
details.put(getResources().getString(R.string.file), true);
if (title != null){
details.put(getResources().getString(R.string.Title),title);
details.put(getResources().getString(R.string.SU).toLowerCase(), Objects.requireNonNull(FirebaseAuth.getInstance().getCurrentUser()).getUid());
}
else
details.put(getResources().getString(R.string.uid), Objects.requireNonNull(FirebaseAuth.getInstance().getCurrentUser()).getUid());
//Make Intent to MainActivity
final Intent intent = new Intent(BaseTaskService.this, SUMain.class)
.putExtra(UploadService.DATA_COLLECTION, path)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
mDatabase.document(path).set(details).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
showFinishedNotification(getString(R.string.upload_success), intent, true, id, true);
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
showFinishedNotification(getString(R.string.upload_failure), intent, false, id, true);
}
});
}
}
}
/**
* Show notification that the activity finished.
*/
void showFinishedNotification(String caption, Intent intent, boolean isSuccess, int id, boolean isUpload) {
createDefaultChannel();
//Since calling a stopSelf() method will kill the service itself and dismissed the very recent Finished notification which is wrong in our case.
//Create a new id for Finished notification that is not bounded from the id of the progress notification, service, and foreground.
String uri = isUpload ? String.valueOf(intent.getParcelableExtra(UploadService.FILE_URI)) : String.valueOf(intent.getParcelableExtra(DownloadService.DOWNLOAD_URI));
//Use the hashcode of current timestamp mixed with some string to make it unique.
int newID = (uri + System.currentTimeMillis()).hashCode();
//Make PendingIntent for notification with the new generated unique id
PendingIntent pendingIntent = PendingIntent.getActivity(this, newID, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
int icon = isSuccess ? R.drawable.ic_done : R.drawable.ic_error_white_24dp;
notification = notificationBuilder
.setProgress(0, 0, false)
.setContentTitle(getString(R.string.app_name))
.setContentIntent(pendingIntent)
.setContentText(caption)
.setContentInfo(null)
.setAutoCancel(true)
.setSmallIcon(icon)
.setOngoing(false)
.build();
//Remove the first notification that has a incremental id which is the notification with progress
notificationManager.cancel(id);
//Show a new notification after removing the progress notification with the new generated unique id
notificationManager.notify(newID, notification);
Log.d(TAG, "Finished Notification: ID = " + newID);
}}

Categories

Resources