I'm trying to run a service which gives notification, if available every few minutes. Since the service will get destroyed after few hours, I thought of making it foreground service. But if I do so, it shows two notification. One is notification column(Thats what I need and got). Another one on Ongoing column which shows icon that work go at all. Its really annoying. The notification code goes like this
Notification.java
n.setLatestEventInfo(getApplicationContext(), "Update", "new update arrived", pIntent);
n.flags = Notification.FLAG_AUTO_CANCEL;
startForeground(2233,n);
n.flags |=Notification.FLAG_NO_CLEAR;
NM = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NM.notify(id,n);
You have to have an ongoing notification to use a foreground so that the user can know it's active. You could schedule an alarm with AlarmManager to start up your service when needed instead of keeping it alive the whole time. You can then do your check at whatever interval you'd like, and your notification will stay alive even if the service closes.
Related
I have an Alarm App that have foreground service with a Heads-Up Notification and that notification have two actions where one send an intent to the Service and can open an activity depending on the app configuration.
The problem is that when i click on a action that sends the intent to the service the notification doesn't hide. This not seems to occur when the intent opens a Activity
I don't want a foreground service without a Notification, i just want it to hide it back to the Notification Drawer when the intent is sent to the service
Here is the code:
NotificationCompat.Builder(mAlarmApplication, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification_alarm)
.setAutoCancel(false)
.setOngoing(true)
.setVibrate(LongArray(0))
.setContentTitle("Title")
.setContentText("Content")
.addAction(0, dismissActionText, dismissPendingIntent)
.setCategory(NotificationCompat.CATEGORY_ALARM)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setContentIntent(alarmScreenPendingIntent)
.setFullScreenIntent(alarmScreenPendingIntent, true)
Here is the link of the app https://play.google.com/store/apps/details?id=com.garageapp.alarmchallenges.
The problem occurs when alarm start and my current solution is to update the old heads up notification with a new one that is not a heads up but the UX is not a good because on Android 8+ the notification new notification pops up aging
Seems like your Notification is bonded with your Service. If so, then you have to kill the notification in Service
Did you try?
public static void cancelNotification(Context ctx, int notifyId) {
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager nMgr = (NotificationManager) ctx.getSystemService(ns);
nMgr.cancel(notifyId);
}
You are using .setOngoing(true) which should not be removed while service is working.
.setAutoCancel(true) will also not working with .setOngoing(true).
You have to use .setOngoing(false) to dismiss the notification.
If you or user remove your foreground notification your service will go to background, I think that best work is to not using heads up notification for foreground by not setting its priority to MAX
Use two notifications at same time one in drawer and another heads up:
-The first notification with priority DEFAULT for starting foreground ( auto cancel set to false and ongoing set to true) show this one with startForground()
-The Second notification (Heads up (Priority MAX) auto cancel set to true and on going set to false) for your actions show this with notifyManager.notify()
These two notifications must have different IDs
another solution:
If you want to use one heads up notification with actions for foreground service you may do this:
use a heads up notification with your action buttons for foreground service when the user clicks actions this action must call the foreground service and then the foreground service could call startForeground (with same id) with a new notification with priority set to default, if your notification could not be updated you may need to call stopForeground(true) or notificationManager.cancel(id) first before calling startForeground with new notification. both of these two notifications should has on going set to true and auto cancel set to false
In my opinion the first solution is better than the second because the notification may not update in second solution.
As the documentation says :
A started service can use the startForeground(int, Notification) API to put the service in a foreground state, where the system considers it to be something the user is actively aware of ...
android system does not allow you to have a foreground service without notification or a hidden notification. and that's because of user awareness of what is happening in his/her system.
also killing the notification will stop your foreground service.
so you never can have both of the options (foreground service and hidden notification)
a not clear solution for your problem:
when you call action that sends the intent to the service, do this with a mediator activity i mean first open an activity and in the activity send intent to the service.
I hope this solve your problem as you told :
The problem is that when i click on a action that sends the intent to the service the notification doesn't hide. This not seems to occur when the intent opens a Activity
I'm trying to develop an Android application which draws a floating overlay on the screen, as it is done by Facebook messenger with chat heads.
I've created an Android service from which I handle the UI. Everything works well, but on some devices the service is stopped very frequently and sometimes it is started again after more than 60 seconds.
I know this is a behavior defined by the Android System, but I was wondering if there is a way to give my service the maximum priority. Is this possible? Could this behavior be worsened by something in my implementation which is wrong?
One option is to make your Service a "Foreground Service" as briefly explained in Android documentation. This means that it shows an icon and possibly some status data in the status bar. Quoting:
A foreground service is a service that's considered to be something
the user is actively aware of and thus not a candidate for the system
to kill when low on memory. A foreground service must provide a
notification for the status bar, which is placed under the "Ongoing"
heading, which means that the notification cannot be dismissed unless
the service is either stopped or removed from the foreground.
In practice you just need to modify the Service's onStartCommand() method to set up the notification and to call startForeGround(). This example is from the Android documentation:
// Set the icon and the initial text to be shown.
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text), System.currentTimeMillis());
// The pending intent is triggered when the notification is tapped.
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
// 2nd parameter is the title, 3rd one is a status message.
notification.setLatestEventInfo(this, getText(R.string.notification_title), getText(R.string.notification_message), pendingIntent);
// You can put anything non-zero in place of ONGOING_NOTIFICATION_ID.
startForeground(ONGOING_NOTIFICATION_ID, notification);
That's actually a deprecated way of setting up a notification but the idea is the same anyway even if you use Notification.Builder.
I have an application that has a reminder feature. When it's time to remind the user of something, my application creates a notification, possibly using FLAG_INSISTENT to ensure the alarm is heard. Once the user interacts with my app to acknowledge the alarm, the app cancels the notification.
The user can launch the app either by pulling down the notification bar and tapping on my notification -- in which case everything is fine -- or by navigating to the app some other way, such as by launching it from the home screen. If the user uses the notification bar method, the FLAG_INSISTENT audio stops when the user touches the notification bar. But here's the problem: if the user enters the app directly without touching the notification bar. the audio for the FLAG_INSISTENT alarm keeps playing indefinitely -- even after my app cancels the notification. The only way a user can stop it is to pull down the notification bar (or reboot the device!).
I've been getting tons of bug reports from angry users ever since the optional FLAG_INSISTENT feature went live. It doesn't seem specific to one platform; users reporting this bug have hardware including a Motorol Razr Maxx HD, Samsung Galaxy Note, and HTC EVO 4G LTE. I've had frustrated users report that they resorted to uninstalling the app to stop the noise, and even then said it wouldn't stop. Searching the web has been fruitless.
The notifications are being created in more-or-less the garden variety way:
notification = new Notification(
R.drawable.icon,
message,
System.currentTimeMillis()
);
if (userDefinedaCustomSound) {
notification.sound = Uri.parse(userSelectedReminderSound);
} else {
notification.defaults |= DEFAULT_SOUND;
}
notification.ledARGB = 0xff00ff00;
notification.ledOnMS = 300;
notification.ledOffMS = 1000;
notification.flags |= Notification.DEFAULT_VIBRATE;
if (userWantsContinuousAlarm) {
notification.flags |= Notification.FLAG_INSISTENT;
}
NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NOTIFICATION_BAR_ID, notification);
And are being cancelled thusly:
nm.cancel(NOTIFICATION_BAR_ID);
I've tried adding the FLAG_AUTO_CANCEL to the notification; that has no effect. As a workaround, I've also tried modifying my cancel method so that it first issues a new notification with no sound, and without FLAG_INSISTENT, then cancels; again, the audio just keeps on playing.
Any ideas?
I faced the same problem. The audio keep on playing after the notification was cancelled.
I formulated this work around,
Perform a normal notification cancelled.mNotificationManager.cancel(getNotificationID(event));
Immediately Create another notification with sound. Use the default Alarm.
Immediately cancel the notification.
Note:
The sound played as part of the notification was not the default.
method getNotificationID(event) always return the same constant for the same event object type.
Notification with sound played using the default will stop when the notification is cancelled.
I set the sound using builder using this
setSound(Uri.parse(this.sharedPreferences.getString(key,"")))
From the observations, I think it might be a bug. The reference to the ringtone object was not properly retained so when the cancel was called, it failed to call on the ringtone .stop() or was unable to do so.
Hope you can used it too.
NotificationManager mNotificationManager = (NotificationManager) this.getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancel(getNotificationID(event));
audioAlarmTriggered.remove(event.sensortype);
NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext());
builder.setAutoCancel(true)
.setSound(ringtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM));
mNotificationManager.notify(getNotificationID(event), builder.build());
mNotificationManager.cancel(getNotificationID(event));
If above code is in your service class. Then I think the problem is when you open app directly instead using notification bar, that time its not calling your service class else you need to call nm.cancel(NOTIFICATION_BAR_ID); from the activity which opens while clicking on notification.
And to do so you need a global class which keeps static NOTIFICATION_BAR_ID, so that will be helpful to you for managing cancel method.
I hope, this will solve your problem.
I've been trying to remove a persistent Notification set by a Service using:
startForeground(1337, notification);
The code I'm using to cancel it:
NotificationManager nManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
nManager.cancel(1337); // cancel existing service notification, doesn't take effect
nManager.cancelAll(); //surpluous, but also doesn't take effect
To clarify why I am doing this: the Service starts with a default persistent Notification. When my app runs, it needs to replace this Notification with another. Using notify() on the existing Notification works perfectly, however, I need it to show the ticker text for the new Notification as well. This is why I decided to remove the existing Notification (using the code above), create a new one, and then I call startForeground() again and pass the new Notification to it, so my Service persists.
The problem is that you're issuing the Notification in an indirect way by using startForeground(). You can't just cancel that Notification for the same reason the system insists on you providing a Notification when starting a foreground Service. As long as your foreground Service is running, that Notification will be there.
In most cases, Services really shouldn't be in the foreground. If you can use a normal priority for your Service, then you can start and stop your Notification normally.
If you're actually doing something that truly does require a foreground Service, and if you really want to show the user a ticker text, I believe your only option is to issue another Notification.
You can always remove notification from a foreground service by callng stopForeground(boolean removeNotification). Then a service exits his foregroundState and once again can be killed by the system when the memory is needed.
You could update the notification by passing in an empty Builder.
if(showNotification){
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setVisibility(Notification.VISIBILITY_SECRET)
.setSmallIcon(R.mipmap.ic_spotify_white_24dp)
.setTicker("Playing Now")
.setContentTitle("Spotify")
.setContentText("Preview");
return mBuilder;
}else{
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
return mBuilder;
}
In my app, I place my Service in the foreground to prevent it from being killed by using:
startForeground(NOTIFY_ID, notification);
This also displays the notification to the user (which is great). The problem is that later I need to update the notification. So I use the code:
notification.setLatestEventInfo(getApplicationContext(), someString, someOtherString, contentIntent);
mNotificationManager.notify(NOTIFY_ID, notification);
The question then is: will doing this knock the Service out of it's special foreground status?
In this answer, CommonsWare indicates that this behavior is possible, but he's not sure. So does anyone know the actual answer?
Note: I am aware that a simple way to get out of this question is to repeatedly call startForeground() every time I want to update the notification. I'm looking to know whether this alternative will also work.
To clarify what has been said here:
From what I understand, if you cancel the notification the service
will cease being a foreground service, so keep that in mind; if you
cancel the notification, you'll need to call startForeground() again
to restore the service's foreground status.
This part of the answer suggest it is possible to remove an ongoing Notification set by a Service by using NotificationManager.cancel() on the persistent Notification.
This is not true.
It's impossible to remove a ongoing notification set by startForeground() by using NotificationManager.cancel().
The only way to remove it, is to call stopForeground(true), so the ongoing Notification is removed, which ofcourse also makes the Service stop being in the foreground. So it's actually the other way around; the Service doesn't stop being in the foreground because the Notification is cancelled, the Notification can only be cancelled by stopping the Service being in the foreground.
Naturally one could call startForeground() after this right away, to restore the state with a new Notification. One reason you would want to do this if a ticker text has to be shown again, because it will only run the first time the Notification is displayed.
This behaviour is not documented, and I wasted 4 hours trying to figure out why I couldn't remove the Notification.
More on the issue here: NotificationManager.cancel() doesn't work for me
The RandomMusicPlayer (archived) app at the Android developer site uses NotificationManager to update the notification of a foreground service, so chances are pretty good that it retains the foreground status.
(See setUpAsForeground() and updateNotification() in the MusicService.java class.)
From what I understand, if you cancel the notification the service will cease being a foreground service, so keep that in mind; if you cancel the notification, you'll need to call startForeground() again to restore the service's foreground status.
When you want to update a Notification set by startForeground(), simply build a new notication and then use NotificationManager to notify it.
The key point is to use the same notification id.
Updating the Notification will NOT remove the Service from the foreground status (this can be done only by calling stopForground );
Example:
private static final int notif_id=1;
#Override
public void onCreate (){
this.startForeground();
}
private void startForeground() {
startForeground(notif_id, getMyActivityNotification(""));
}
private Notification getMyActivityNotification(String text){
// The PendingIntent to launch our activity if the user selects
// this notification
CharSequence title = getText(R.string.title_activity);
PendingIntent contentIntent = PendingIntent.getActivity(this,
0, new Intent(this, MyActivity.class), 0);
return new Notification.Builder(this)
.setContentTitle(title)
.setContentText(text)
.setSmallIcon(R.drawable.ic_launcher_b3)
.setContentIntent(contentIntent).getNotification();
}
/**
this is the method that can be called to update the Notification
*/
private void updateNotification() {
String text = "Some text that will update the notification";
Notification notification = getMyActivityNotification(text);
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(notif_id, notification);
}