Android Workmanger PeriodicWorkRequest API work only once? - android

Am Using androidx Work manager API, in Work manager am using PeriodicWorkRequest to trigger the Work for every 4 hours. But it works only once after run the application.
PeriodicWorkRequest Coding:-
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
PeriodicWorkRequestpendingCampaignWork = new PeriodicWorkRequest.Builder(PendingCampaignWorker.class, 4, TimeUnit.HOURS)
.setConstraints(constraints)
.build();
Work Manger Code to Enqueue the Request:-
WorkManager.getInstance().enqueueUniquePeriodicWork(LATEST_CAMPAIGN_WORK, ExistingPeriodicWorkPolicy.KEEP, pendingCampaignWork);
For testing am change System time Manually to 4 hours after run the application in emulator to trigger the Work.
Is there any issue in my code help me to solve the issue.
Update:-
Work Manager is working fine, its not working based on System time as m.hassan said in answer section. Am test to trigger the work for every 20 minutes, its working fine.

Work Manager Not not based on system time. You can make a periodic work request of 15 minutes. This way you can test your code.
here's an example:
My Periodic Work Request:
private static final String TAG = "PeriodicWorkTag";
private static final int PERIODIC_WORK_INTERVAL = 15;
public static void schedulePeriodicWork() {
androidx.work.PeriodicWorkRequest periodicWorkRequest = new androidx.work.PeriodicWorkRequest.Builder(PeriodicWorkRequest.class, PERIODIC_WORK_INTERVAL,
TimeUnit.MINUTES)
.addTag(TAG)
.build();
WorkManager.getInstance().enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.KEEP, periodicWorkRequest);
}
public static void cancelPeriodicWork() {
WorkManager.getInstance().cancelAllWorkByTag(TAG);
}
My Worker Class:
public static final String CHANNEL_ID = "VERBOSE_NOTIFICATION" ;
public PeriodicWorkRequest(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
#NonNull
#Override
public Result doWork() {
showNotification(getApplicationContext());
return Result.SUCCESS;
}
private void showNotification(Context context) {
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("My notification")
.setContentText("ddd")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText("ddd"))
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "Channel_name";
String description = "description";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(100, mBuilder.build());
}

This did the trick in my case: Add your app to IGNORE_BATTERY_OPTIMIZATIONS list.
#SuppressLint("BatteryLife")
public void showIgnoreBatteryOpt() {
String packageName = getPackageName();
Intent intent = new Intent();
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (!pm.isIgnoringBatteryOptimizations(packageName)) {
Log.d(TAG, "showIgnoreBatteryOpt: NOT ignoring");
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
startActivity(intent);
}
else {
Log.d(TAG, "showIgnoreBatteryOpt: ignoring");
}
}
Add to AndroidManifest.xml:
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>

Related

How can I access objects from my Activity in a Worker? (to periodically change a notification)

I would like to periodically change a notification's text in a Worker. (androidx.work.WorkManager)
My MainActivity looks like this
public class MainActivity extends AppCompatActivity {
...
private NotificationManagerCompat notificationManagerCompat;
private NotificationCompat.Builder notificationBuilder;
...
private void startNotification() {
...
notificationBuilder =
new NotificationCompat.Builder(getApplicationContext(), warnotifier_notification_channel)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle(notificationTitle)
.setContentText(notificationText)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_LOW)
.setOngoing(true);
notificationManagerCompat = NotificationManagerCompat.from(getApplicationContext());
notificationManagerCompat.notify(1, notificationBuilder.build());
PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(NotificationWorker.class, PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS, TimeUnit.MILLISECONDS)
.addTag(workTag)
.build();
WorkManager.getInstance(getApplicationContext()).enqueue(periodicWorkRequest);
}
...
}
and my Worker looks like this
public class NotificationWorker extends Worker {
public NotificationWorker(#NonNull Context context, #NonNull WorkerParameters params) {
super(context, params);
}
#NonNull
#Override
public Result doWork() {
String notificationText = "Time: " + calendar.get(Calendar.HOUR_OF_DAY) + ":" + calendar.get(Calendar.MINUTE) + ":" + calendar.get(Calendar.SECOND);
notificationBuilder.setContentText(notificationText);
notificationManagerCompat.notify(1, notificationBuilder.build());
return Result.success();
}
}
Unfortunately, Android does not allow me to put the Worker as a nested class in my MainActivity, and therefore I can't access the NotificationManagerCompat and NotificationCompat.Builder instances like above.
I know I can pass simple data with periodicWorkRequest.setInputData(inputData) to the Worker but I don't think that helps ...
Any ideas? Thanks in advance.
Unfortunately, Android does not allow me to put the Worker as a nested
class in my MainActivity, and therefore I can't access the
NotificationManagerCompat and NotificationCompat.Builder instances
like above.
Why you need to add your NotificationWorker class within the MainActivity?
As you mentioned you just want to access NotificationManagerCompat and NotificationCompat.Builder from the Worker class and there is no restriction to that, so to build your notification you already have a context passed to Worker class constructor, and also you can still call getApplicationContext() from the Worker class.
I have tested that without any problem.
Hope that helps. I am welcome if you have any queries.
Update
In my Worker class I wanted to access the notificationManagerCompat
and notificationBuilder instances I created in MainActivity.
You don't have to create notificationManagerCompat & notificationBuilder instances in MainActivity, you can normally create them in NotificationWorker
Here is a demo from your code
public class NotificationWorker extends Worker {
private final NotificationManagerCompat notificationManagerCompat;
private final NotificationCompat.Builder notificationBuilder;
public NotificationWorker(#NonNull Context context, #NonNull WorkerParameters params) {
super(context, params);
PendingIntent pendingIntent = PendingIntent.getActivity
(context, 0, new Intent(context, MainActivity.class),
PendingIntent.FLAG_UPDATE_CURRENT);
notificationBuilder =
new NotificationCompat.Builder(getApplicationContext(), warnotifier_notification_channel)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle(notificationTitle)
.setContentText(notificationText)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_LOW)
.setOngoing(true);
notificationManagerCompat = NotificationManagerCompat.from(getApplicationContext());
}
#NonNull
#Override
public Result doWork() {
Calendar calendar = new GregorianCalendar();
String notificationText = "Time: " + calendar.get(Calendar.HOUR_OF_DAY) + ":" + calendar.get(Calendar.MINUTE) + ":" + calendar.get(Calendar.SECOND);
notificationBuilder.setContentText(notificationText);
notificationManagerCompat.notify(1, notificationBuilder.build());
return Result.success();
}
}
And you can get notificationTitle, notificationText from res/string using R.string.XX, and notification_icon from res/drawable using R.drawable.XX.
With this you can use NotificationManagerCompat and NotificationCompat.Builder from your Worker, all you need just a context, no need to activity.
hope this answers your question.
You can create a notification with same ID (So maintain a constant ID for your notification) and notify. It updates the existing one automatically
NotificationManager notificationManager = (NotificationManager) getSystemService(
Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
Create a notification object with same ID as previous one and use notify to update the existing one.
}

Workmanager not working when app is in background

I'm trying to periodically run a service even when the app is killed or is in the background using workManager.
My RequestService class is given below:-
public class RequestService extends Worker {
public RequestService(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
#NonNull
#Override
public Result doWork() {
displayNotification("MY Worker", "Background work Started");
Log.i("BackJob","Running");
return Result.SUCCESS;
}
private void displayNotification(String title, String task){
NotificationManager notificationManager = (NotificationManager)getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("MyApp","My Notifications",
NotificationManager.IMPORTANCE_HIGH);
notificationManager.createNotificationChannel(channel);
}
NotificationCompat.Builder notification = new NotificationCompat.Builder(getApplicationContext(), "My Notifications").
setContentTitle(title).setContentText(task)
.setSmallIcon(R.mipmap.ic_launcher);
notificationManager.notify(130, notification.build());
}}
This is the main activity code:-
final PeriodicWorkRequest WorkReq = new PeriodicWorkRequest.Builder(RequestService.class,15,TimeUnit.MINUTES).build();
WorkManager.getInstance().enqueue(WorkReq);
The issue is if the app is killed or is in the background then workmanager stops working.
I'm testing this on a samsung device with android version pie.
P.S :- if the app is open then i see notifications continuously after 15 mins....however as soon as i close the app.....it stops working.....and there are no more notifications
You can use foreground Service for this , Foreground Service work when app is in background.
add this method in downork method
setForegroundAsync(createForegroundInfo(progress));
Override this method in workermanager class
#NonNull
private ForegroundInfo createForegroundInfo(#NonNull String progress) {
Context context = getApplicationContext();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel chan = new NotificationChannel("1", "channelName", NotificationManager.IMPORTANCE_NONE);
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
assert manager != null;
manager.createNotificationChannel(chan);
}
Notification notification = new NotificationCompat.Builder(context, "1")
.setContentTitle("title")
.setTicker("title")
.setSmallIcon(R.drawable.ic_launcher_background)
.setOngoing(true)
.build();
return new ForegroundInfo(1,notification);
}
Now you app will work in the background.
As Per the PeriodicWorkRequest.Builder official documentation available here
The intervalMillis must be greater than or equal to PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS
This value is currently set to 900000 ms i.e, 15 minutes.
This is a working example that currently shows any notification regarding the version of the SO. But seemingly the problem can be related with the notify method from NotificationManagerCompat
private void makeStatusNotification(String message, Context context) {
String channelId = context.getString(R.string.worker_sync_notif_channel_id);
// Make a channel if necessary
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Create the NotificationChannel, but only on API 26+
CharSequence name = context.getString(R.string.worker_sync_notif_channel_name);
String description = context.getString(R.string.worker_sync_notif_channel_description);
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel(channelId, 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, channelId)
.setSmallIcon(R.drawable.ic_cloud_upload)
.setContentTitle(context.getString(R.string.worker_sync_notif_title))
.setContentText(context.getString(R.string.worker_sync_notif_subject))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(message))
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setVibrate(new long[0])
.setAutoCancel(true);
// Show the notification
NotificationManagerCompat.from(context).notify(NOTIFICATION_ID, builder.build());
}

Android OneTime IntentService dies when app is killed

I need to run a task after 10 seconds, even if the app is closed. I created IntentService:
class SomeService: IntentService() {
override fun onHandleIntent(intent: Intent?) {
Thread.sleep(10_000)
somefunction()
}
}
Intent service dies after app dies.
I can't relaunch it with BroadcastReceiver, because its one-time service, which must perform this action after 10 seconds
Quoting Android Developer Guide
IntentService is subject to all the background execution limits
imposed with Android 8.0 (API level 26)
You can read more about the restrictions here https://developer.android.com/about/versions/oreo/background
Some solutions you can try are
1)Have a foreground service (Attach a notification to the service)
In Java, the way I do is I have two utility methods created
public static void startNotificationAlongWithForegroundService(Service service,String CHANNEL_ID_FOREGROUND,String CHANNEL_NAME_FOREGROUND, String title, String body, Integer notification_id) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(service, CHANNEL_ID_FOREGROUND)
.setContentTitle(title)
.setContentText(body)
.setOngoing(true)
.setSmallIcon(R.drawable.ic_launcher)
.setProgress(100, 0, true);
NotificationManager mNotificationManager = (NotificationManager) service.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel = mNotificationManager.getNotificationChannel(CHANNEL_ID_FOREGROUND);
if(channel==null) {
channel = new NotificationChannel(CHANNEL_ID_FOREGROUND,CHANNEL_NAME_FOREGROUND, NotificationManager.IMPORTANCE_NONE);
channel.setShowBadge(false);
if (mNotificationManager != null) {
mNotificationManager.createNotificationChannel(channel);
}
}
service.startForeground(notification_id, builder.build());
}
}
public static void destroyForegroundService(Service context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.stopForeground(true);
}
}
And in your service
#Override
protected void onHandleIntent(Intent intent) {
Utils.startNotificationAlongWithForegroundService(this,"channel_id","channelname","title","body",123);
//your work
Utils.destroyForegroundService(this);
}
2)Use JobService/Workmanager
I will update the answer with the examples on this shortly if you are not comfortable with using Job services/WorkManager.

Periodic work requests using WorkManager not working

i am trying to write a periodic workmanager script but it just run when i open the app and it just run one time (not periodic) !
here is my main activity :
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_work);
Intent intent = new Intent();
PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this,0,intent,0);
NotifyWorker.pendingIntent = pendingIntent;
NotifyWorker.context = this;
PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(NotifyWorker.class, 1, TimeUnit.MINUTES).build();
WorkManager.getInstance().enqueue(periodicWorkRequest);
}
}
and this is my dowork method :
public Result doWork() {
Log.i("wd","wd");
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context,"ctx")
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(),R.mipmap.ic_launcher))
.setSmallIcon(R.drawable.logo)
.setContentTitle("Title")
.setContentText("Desc")
.setContentIntent(pendingIntent);
android.app.NotificationManager notificationManager =
(android.app.NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 , notificationBuilder.build());
return Result.SUCCESS;
}
why its not run every 1 minute ? what i miss ?
Per the PeriodicWorkRequest.Builder documentation:
The intervalMillis must be greater than or equal to PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS
That value is currently set to 900000 - i.e, 15 minutes.
First of all, you can disagree with my answer but here is the hack which I used in my project and this work very accurately without gives any problem.
It's time to see the code. One thing I pointed later and must read this point after the code. SECTION IMP
//this code in your activity, fragment or any other class
notify_switch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked)
{
OneTimeWorkRequest track_share_market = new OneTimeWorkRequest.Builder(NotificationWorker.class).setInitialDelay(1,TimeUnit.MINUTES).addTag("Stock_Market").build();
WorkManager.getInstance().enqueue(track_share_market);
Log.d("RishabhNotification","SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSs");
}
else {
Log.d("RishabhNotification","FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
WorkManager.getInstance().cancelAllWorkByTag("Stock_Market");
}
}
});
Now your Worker class Code
public class NotificationWorker extends Worker {
public NotificationWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
#NonNull
#Override
public Result doWork() {
try {
//Some heavy operation as you want there is no need to make another thread here
//track some website for weather changes or stock market changes
//In my case doWork takes only 10sec for executing this method
ShowNotification("Market Up","Gold Price goes upto ₹25,000 ","Check the app for the new update");
StartNewRequest();
return Result.success();
} catch (Exception e) {
e.printStackTrace();
StartNewRequest();
Log.d("RishabhNotification","ERERERERERERERERERERERERERERERERERERERERERERERERERERERE");
return Result.failure();
}
}
private void StartNewRequest()
{
OneTimeWorkRequest track_market = new OneTimeWorkRequest.Builder(NotificationWorker.class).setInitialDelay(1,TimeUnit.MINUTES).addTag("Stock_Market").build();
WorkManager.getInstance().enqueue(track_market);
}
private void ShowNotification(String Message, String name, String Information)
{
NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
String NOTIFICATION_CHANNEL_ID = "my_channel_id_01";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "Stock Market", NotificationManager.IMPORTANCE_HIGH);
// Configure the notification channel.
notificationChannel.setDescription("Channel description");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.GREEN);
notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
notificationChannel.enableVibration(true);
notificationChannel.setSound(null,null );
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
notificationManager.createNotificationChannel(notificationChannel);
}
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(getApplicationContext(), NOTIFICATION_CHANNEL_ID);
Uri uri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
notificationBuilder.setAutoCancel(false)
.setDefaults(Notification.DEFAULT_SOUND|Notification.DEFAULT_VIBRATE|Notification.DEFAULT_LIGHTS)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setSound(uri)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setPriority(Notification.PRIORITY_MAX)
.setContentTitle(Message)
.setContentText(name)
.setContentInfo(Information);
notificationManager.notify(/*notification id*/1, notificationBuilder.build());
}
}
Now Read the SECTION IMP point
This Code perfectly working in Emulator, Pixel phone, Samsung phone, Moto phone, Asus Phone, One plus phone but this same code I tested in the Xioami Devices and Huawei devices they both devices not run the code for every specific time interval(They both run the code but time may be changed) which I define in my code. I don't know why is this happen on both devices. Maybe some optimization. Check this link for more https://www.reddit.com/r/androiddev/comments/9ra0iq/workmanager_reliability_for_periodic_tasks_on/
I have not tested this code in vivo and Oppo devices.

Android foreground service notification not showing

I am trying to start a foreground service. I get notified that the service does start but the notification always gets suppressed. I double checked that the app is allowed to show notifications in the app info on my device. Here is my code:
private void showNotification() {
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setAction(Constants.ACTION.MAIN_ACTION);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
Bitmap icon = BitmapFactory.decodeResource(getResources(),
R.mipmap.ic_launcher);
Notification notification = new NotificationCompat.Builder(getApplicationContext())
.setContentTitle("Revel Is Running")
.setTicker("Revel Is Running")
.setContentText("Click to stop")
.setSmallIcon(R.mipmap.ic_launcher)
//.setLargeIcon(Bitmap.createScaledBitmap(icon, 128, 128, false))
.setContentIntent(pendingIntent)
.setOngoing(true).build();
startForeground(Constants.FOREGROUND_SERVICE,
notification);
Log.e(TAG,"notification shown");
}
Here is the only error I see in relation:
06-20 12:26:43.635 895-930/? E/NotificationService: Suppressing notification from the package by user request.
It's because of Android O bg services restrictions.
So now you need to call startForeground() only for services that were started with startForegroundService() and call it in first 5 seconds after service has been started.
Here is the guide - https://developer.android.com/about/versions/oreo/background#services
Like this:
//Start service:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(new Intent(this, YourService.class));
} else {
startService(new Intent(this, YourService.class));
}
Then create and show notification (with channel as supposed earlier):
private void createAndShowForegroundNotification(Service yourService, int notificationId) {
final NotificationCompat.Builder builder = getNotificationBuilder(yourService,
"com.example.your_app.notification.CHANNEL_ID_FOREGROUND", // Channel id
NotificationManagerCompat.IMPORTANCE_LOW); //Low importance prevent visual appearance for this notification channel on top
builder.setOngoing(true)
.setSmallIcon(R.drawable.small_icon)
.setContentTitle(yourService.getString(R.string.title))
.setContentText(yourService.getString(R.string.content));
Notification notification = builder.build();
yourService.startForeground(notificationId, notification);
if (notificationId != lastShownNotificationId) {
// Cancel previous notification
final NotificationManager nm = (NotificationManager) yourService.getSystemService(Activity.NOTIFICATION_SERVICE);
nm.cancel(lastShownNotificationId);
}
lastShownNotificationId = notificationId;
}
public static NotificationCompat.Builder getNotificationBuilder(Context context, String channelId, int importance) {
NotificationCompat.Builder builder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
prepareChannel(context, channelId, importance);
builder = new NotificationCompat.Builder(context, channelId);
} else {
builder = new NotificationCompat.Builder(context);
}
return builder;
}
#TargetApi(26)
private static void prepareChannel(Context context, String id, int importance) {
final String appName = context.getString(R.string.app_name);
String description = context.getString(R.string.notifications_channel_description);
final NotificationManager nm = (NotificationManager) context.getSystemService(Activity.NOTIFICATION_SERVICE);
if(nm != null) {
NotificationChannel nChannel = nm.getNotificationChannel(id);
if (nChannel == null) {
nChannel = new NotificationChannel(id, appName, importance);
nChannel.setDescription(description);
nm.createNotificationChannel(nChannel);
}
}
}
Remember that your foreground notification will have the same state as your other notifications even if you'll use different channel ids, so it might be hidden as a group with others. Use different groups to avoid it.
The problem was i am using Android O and it requires more information. Here is the successful code for android O.
mNotifyManager = (NotificationManager) mActivity.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) createChannel(mNotifyManager);
mBuilder = new NotificationCompat.Builder(mActivity, "YOUR_TEXT_HERE").setSmallIcon(android.R.drawable.stat_sys_download).setColor
(ContextCompat.getColor(mActivity, R.color.colorNotification)).setContentTitle(YOUR_TITLE_HERE).setContentText(YOUR_DESCRIPTION_HERE);
mNotifyManager.notify(mFile.getId().hashCode(), mBuilder.build());
#TargetApi(26)
private void createChannel(NotificationManager notificationManager) {
String name = "FileDownload";
String description = "Notifications for download status";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel mChannel = new NotificationChannel(name, name, importance);
mChannel.setDescription(description);
mChannel.enableLights(true);
mChannel.setLightColor(Color.BLUE);
notificationManager.createNotificationChannel(mChannel);
}
For me everything was set correctly (also added FOREGROUND_SERVICE permission to manifest),
but I just needed to uninstall the app and reinstall it.
If none of the above worked you should check if your notification id is 0 ...
SURPRISE!! it cannot be 0.
Many thanks to #Luka Kama for this post
startForeground(0, notification); // Doesn't work...
startForeground(1, notification); // Works!!!
if you are targeting Android 9(Pie) api level 28 and higher than you should give FOREGROUND_SERVICE permission in manifest file.see this link : https://developer.android.com/about/versions/pie/android-9.0-migration#bfa
I can not believe it. In my case, after adding 'android:name=".App"' to AndroidManifest.xml, the notification started showing.
Example:
<application
android:name=".App"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
For Android API level 33+ you need to request POST_NOTIFICATIONS runtime permission. Although this doesn't prevent the foreground service from running, it's still mandatory to notify as we did for < API 33:
Note: Apps don't need to request the POST_NOTIFICATIONS permission in order to launch a foreground service. However, apps must include a notification when they start a foreground service, just as they do on previous versions of Android.
See more in Android Documentation.
In my case, it was caused by me using IntentService.
In short, if you want a foreground service then subclass Service.

Categories

Resources