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.
Related
We are working on notification trampolines on Android 12.
Originally our app launches an activity by a broadcast receiver.
I found out that using PendingIntent.getActivity instead of PendingIntent.getBroadcast would solve the problem.
Regarding this, I have a following concern.
When the broadcast receiver is used, i.e. when PendingIntent.getBroadcast is used, I programmed so that the broadcast receiver determines whether to launch the app.
However, I no longer use the broadcast receiver due to notification trampolines. Therefore, PendingIntent.getActivity launches the app without choice.
I would like to know if there is any way to determine whether to launch the app depending of the state of app without using the broadcast receiver.
For example;
when App is in state A:Launch the app with a push notification tap
when App is in state B:NOT launch the app with a push notification tap
sort of workaround would be to launch some dedicated Activity, which may be set as fully transparent without any enter/exit animation, noHistory flag etc. and in there you may run your checking logic - starting "real" Activity or just finish() if there is no need
I'm using a transparent activity to handle this issue. all the notification related works are handled in the transparent activity.
Intent intent = new Intent(mContext, NotificationActivity.class);
intent.putExtra("notification", parseInt(this.mActionDetail.getNotifyId()));
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
builder.setContentIntent(pendingIntent);
builder.setAutoCancel(true);
notificationManager.notify(parseInt(this.mActionDetail.getNotifyId()), builder.build());
create a transparent activity NotificationActivity.class then you can identify the application state then you can decide the action
I need to remove the notification.without affecting the foreground service of the application.thanks in advance
Notification note = new Notification(R.drawable.ic_blank,"",System.currentTimeMillis());
Intent i=new Intent(this, MyLocationListener.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pi=PendingIntent.getActivity(this, 0,i, 0);
note.setLatestEventInfo(this, "","", pi);
note.flags |= Notification.FLAG_NO_CLEAR;
startForeground(42, note);
Android OS don’t like you to do this because users are entitled to know you are running a foreground serivce on their devices.
But if you must remove notification of foreground service :
In order to remove the notification icon in the notification area (the status bar) while foreground service still running :
Just set the priority to minimum (-2) in the notification builder:
for example:
/* (Notification.PRIORITY_MIN) will remove the notification in statusbar */
builder.setPriority(Notification.PRIORITY_MIN)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Service Started")
.setTicker("Music Playing")
.setWhen(System.currentTimeMillis());
This will only remove the small notification icon in the notification area.
if you also need to get rid of the detail notification rectangle in the notification drawer :
then what you need to do is more complex:
you need to start your service as foreground, then start another foreground service with the same notification ID as you have in your original service.
Then close ( stopself() ) the new foreground service, and Android system will remove the notification (while your original service that started previously will stay in foreground without the notification).
This works fine in 5.1.1, I don’t know if android team already close this breach in marshmallow .
BTW:
In order to do this there is also a non-programmatically way :
Go to settings -> applications -> application manager find your application and press on it.
You will get inside your application info.
Disable the “show notifications” option in your application info.
This will get rid of all notifications for your app but it also disable toast messages..
I don’t think there is a way to disable this option in settings programmatically from inside the application - I think android prevent it for security reasons. If anyone knows how to change this programmatically please tell..
if while trying to avoid the notification detail rectangle in the drawer you will remove these lines in your notification builder:
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Service Started")
.setTicker("Music Playing")
.setWhen(System.currentTimeMillis());
Then Android system will keep on showing a notification rectangle about your service (with the title “This service is running, touch for more information or stop the service ” ) and pressing on this rectangle will lead the user to Your application info on settings -> applications -> application manager with option to “force stop” this service.
Regarding that you can read more here https://plus.google.com/105051985738280261832/posts/MTinJWdNL8t
hope it helps :-)
Adding this line builder.setPriority(Notification.PRIORITY_MIN) will remove the notification icon from the status bar and lock screen.
Also removing or commenting builder.setSmallIcon(R.drawable.ic_launcher) removes the notification icon even when you scroll down notifications when device is unlockedbut i m not sure how it will work in android N
When I swipe my app from recent tasks, my service stops, then restarts in a few seconds. I'd like it to behave more like pandora.
When you're playing music with pandora and swipe pandora out of recent tasks, the music continues to play without stopping at all. I'm trying to implement this behavior in my app.
I saw this post: Android: keeping a background service alive (preventing process death) which seems to indicate that the way to do this was to use the startForeground method.
I copied this code from http://developer.android.com/guide/components/services.html#Foreground
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);
And made sure that my notification id was not zero (it's 1). I also return START_STICKY. Any clue what I'm doing wrong?
EDIT: The above behavior happens on 4.2. On 4.4, the notification doesn't go away. However, the thread I'm running inside the service stops and does not restart. At least on 4.2 it restarts :/
My android application starts a service to listen to headset buttons. While the service is running, I want to show a notification. Because it's also important it does not get killed, I decided to use the startForeground function in my service.
in the OnCreate of the service, I start BuildNotification():
public void BuildNotification() {
// Make sure the launch mode of the activity is singleTask, otherwise it will create a new one
Intent intent = new Intent(this, ListItemsActivityScroll.class);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0);
// Build notification
note = new NotificationCompat.Builder(this)
.setContentTitle(getString(R.string.notification_text))
.setSmallIcon(R.drawable.vp_launcher)
.setContentText(getString(R.string.notification_content))
.setContentIntent(pIntent).build();
startForeground(1, note);
}
The first time the service is started, the notification gets displayed and stays in the status bar until the service is destroyed. However, if the service gets created for a second time, it shows only for a couple of seconds.
After it disappeared, the service is still running. I also executer 'adb shell dumpsys activity services', which does show the service to be running in the foreground and gives me also the correct flags set to the notitication:
isForeground=true foregroundId=1 foregroundNoti=Notification(contentView=com.example.mediabuttontest/0x10900a7 vibrate=null,sound=null,defaults=0x0,flags=0x62)
The 0x62 flags would mean the following are active: FLAG_FOREGROUND_SERVICE, FLAG_NO_CLEAR, FLAG_ONGOING_EVENT
Which I think is correct for keeping the notification active.
Does anyone understand this behaviour? Why it does work the first time the service is created, but not the second time? Is there any error in my code?
EDIT: Thanks for your time and comments, I've created another test application and started removing code until the problem disappeared. In the end, it was caused by enabling / disabling a broadcast receiver component:
pm.setComponentEnabledSetting(mRemoteControlResponder,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
Somehow, this makes the notification disappear. In the document it also mentions about 'DONT_KILL_APP' can make your application behave unpredicatable:
Be careful when you set this since changing component states can make the containing application's behavior unpredictable.
I guess that's true :)
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);
}