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());
}
Related
Foreground service notification shows too slowly on Android 12. Used ContextCompat.startForegroundService(...) and mContext.startForegroundService(...). It still shows in 5-10 seconds.
Here is an example of my code:
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "Counting steps", NotificationManager.IMPORTANCE_DEFAULT);
channel.enableVibration(false);
channel.setSound(null, null);
channel.setShowBadge(false);
notificationManager.createNotificationChannel(channel);
}
}
The onStartCommand method:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String input = intent.getStringExtra("numberOfSteps");
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
Notification.Builder notificationBuilder = new Notification.Builder(this, CHANNEL_ID)
.setContentTitle("Counting steps")
.setContentText(input)
.setSmallIcon(R.drawable.ic_baseline_directions_walk_24)
.setContentIntent(pendingIntent);
startForeground(FOREGROUND_ID, notificationBuilder.build());
}
return START_STICKY;
}
How can I start or show a foreground service notification quickly?
Services that show a notification immediately
If a foreground service has at least one of the following
characteristics, the system shows the associated notification
immediately after the service starts, even on devices that run Android
12 or higher:
The service is associated with a notification that includes action
buttons. The service has a foregroundServiceType of
mediaPlayback, mediaProjection, or phoneCall. The service
provides a use case related to phone calls, navigation, or media
playback, as defined in the notification's category
attribute. The service has opted out of the behavior
change by passing FOREGROUND_SERVICE_IMMEDIATE into
setForegroundServiceBehavior() when setting up the
notification.
On Android 13 (API level 33) or higher, if the user denies the
notification permission, they still see notices related to foreground
services in the Foreground Services (FGS) Task Manager but don't see
them in the notification drawer.
See: Services that show a notification immediately
Java example code:
Notification.Builder notificationBuilder = new Notification.Builder(this, CHANNEL_ID)
.setContentTitle("Counting steps")
.setContentText(message)
.setSmallIcon(R.drawable.your_cool_icon)
.setContentIntent(pendingIntent);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
notificationBuilder.setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE);
}
Kotlin example:
val notificationBuilder: Notification.Builder =
Notification.Builder(this, CHANNEL_ID)
.setContentTitle("Notification title")
.setContentText("Content title")
.setSmallIcon(R.drawable.your_cool_icon)
.setContentIntent(pendingIntent)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
notificationBuilder.setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE)
}
I have a firebase push notifications that sends text messages. My notifications appear in API 26 onward, but on APIs lower, (currently testing with API 22) and the messages are successfully sent, but they dont appear on the (API 22) device. What could be the problem?
public class FirebaseMessagingService extends com.google.firebase.messaging.FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
createNotificationChannel();
String messageTitle = remoteMessage.getNotification().getTitle();
String messageBody = remoteMessage.getNotification().getBody();
String click_action = remoteMessage.getNotification().getClickAction();
String dataMessage = remoteMessage.getData().get("message");
String dataFrom = remoteMessage.getData().get("from_user_id");
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, getString(R.string.default_notification_channel_id))
.setSmallIcon(R.mipmap.ic_launcher_round)
.setContentTitle(messageTitle)
.setContentText(messageBody)
.setPriority(NotificationCompat.PRIORITY_HIGH);
Intent intent = new Intent(click_action);
intent.putExtra("message", dataMessage);
intent.putExtra("from_user_id", dataFrom);
PendingIntent resultIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(resultIntent);
int mNotificationId = (int) System.currentTimeMillis();
NotificationManager mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNotifyMgr.notify(mNotificationId, builder.build());
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "Personal Notifications";
String desc = "Include all the personal notifications";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel notificationChannel = new NotificationChannel(getString(R.string.default_notification_channel_id), name, importance);
notificationChannel.setDescription(desc);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(notificationChannel);
}
}
}
What could be the problem?
If you have situation, when notification appears in status bar, but a floating window not popping up, you should add in your NotificationCompat.Builder
.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE)
because such notifications are called a heads-up notifications and it should have high priority and use ringtones or vibrations on devices running Android 7.1 (API level 25) and lower
The issue is you have targeted Oreo and above in your createNotificationsChannel.
Exact place you target oreo and above is:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
The reason why this has happened will be because of the code listed below since it was added in API level 26. You will need to find an alternative version for lower levels.
notificationManager.createNotificationChannel(notificationChannel);
I had this a while ago. Keep your createNotificationChannel() method in your main class. However, I suggest creating a different class with a static method (to create your notification) then just call it in the FirebaseMessagingService class. Try this:
public class NotificationHelper {
public static void displayNotification(Context context,String title,String body){
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context,CHANNELID)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(title)
.setContentText(body)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
NotificationManagerCompat managerCompat = NotificationManagerCompat.from(context);
managerCompat.notify(1,mBuilder.build());
}
}
Then in your FMService class, just call the static method after your notification channel like so:
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
createNotificationChannel();
if(remoteMessage.getNotification()!=null){
String messageTitle = remoteMessage.getNotification().getTitle();
String messageBody = remoteMessage.getNotification().getBody();
NotificationHelper.displayNotification(getApplicationContext(),messageTitle,messageBody);
}
You should be fine.
I try to create android notification, when i click in a button but does not work.
this is the code that i write in button
NotificationManager Nm;
public void Notify(View view) {
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setContentTitle("LOGIN")
.setContentText("You are login successfully")
.setSmallIcon(R.drawable.done);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, mBuilder.build());
}
As already stated by Ikazuchi, for android versions since android 8 you'll need to add a notification channel. This can be done, as it's shown in the documentation here: https://developer.android.com/training/notify-user/build-notification#java, like this:
createNotificationChannel();
Notification notification = new NotificationCompat.Builder(this, "channelID")
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("My notification")
.setContentText("Much longer text that cannot fit one line...")
.build();
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel serviceChannel = new NotificationChannel(
"channelID",
"Channel Name",
importance
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
I'm using a foreground service with notifications. It it's important that my notification pops up by itself and not just when you drag down the top bar.
It's working most of the time. Except on Xiaomi phones. And weirdly enough it just stopped working on a Pixel 2 API 29 as well...
I know they don't show up on older APIs if there is no sound OR vibration. Maybe it has something to do with that.
StatusNotification statusNotification = new StatusNotification(getApplicationContext());
startForeground(1, statusNotification.notification());
...
public class StatusNotification {
Context context;
long[] shortVibration;
StatusNotification(Context context){
this.context = context;
shortVibration = new long[] {0L, 100L, 0L};
// just {100L} doesn't vibrate at all
// but it has to be one short vibration and not the default one
// VibrationEffect.createOneShot() is only for Oreo and higher
createNotificationChannel();
}
void createNotificationChannel(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager manager = context.getSystemService(NotificationManager.class);
NotificationChannel channel2 = new NotificationChannel("channel2", "Channel 2", NotificationManager.IMPORTANCE_HIGH);
channel2.setDescription("Channel 2");
channel2.enableVibration(true);
channel2.setSound(null, null);
channel2.setVibrationPattern(shortVibration);
manager.createNotificationChannel(channel2);
}
}
Notification notification(){
return new NotificationCompat.Builder(context, "channel2")
.setProgress(100,100, false)
.setContentTitle("Title")
.setColor(context.getResources().getColor(R.color.colorPrimary))
.setSmallIcon(R.drawable.ic)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
.setVibrate(shortVibration)
.build();
}
}
Use case is I have to send logout request to server when app get killed from recent lists. I use onTaskRemoved to handle that however in Android O and P I get notification bar saying "app is running" that I want to avoid. Here is how I run foreground service:
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
channelId = "my_service_channel_id";
String channelName = "My Foreground Service";
NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_LOW);
channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
channel.setSound(null, null);
notificationManager.createNotificationChannel(channel);
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this, channelId)
.setContentTitle("")
.setAutoCancel(true)
.setContentText("");
startForeground(NOTIFY_ID, builder.build());
//notificationManager.cancel(NOTIFY_ID); // It doesn't remove notification
//notificationManager.deleteNotificationChannel(channelId); // it causes crash
}
I already tried JobScheduler but onTaskRemoved doesn't get trigger. Any helps would be appreciated.