Android startForeground notification disappears - android

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 :)

Related

Android 12 - About Correspondence to notification trampoline

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

Multiple fullscreen android notifications at the same time not stacking

I am working on an android project that has an alarm clock like functionality.
I schedule an intentService for each alarm instance (fires at 9pm, for example.), this intentService builds the notification and displays it. The notification includes a fullScreenIntent, which works as expected and launches the activity. I use the following code to do this:
alarmActivityIntent = new Intent(this, AlarmActivity.class);
PendingIntent alarmActivityPendingIntent = PendingIntent.getActivity(this, alertSchedule.getIntentId(), alarmActivityIntent, PendingIntent.FLAG_CANCEL_CURRENT);
mBuilder.setFullScreenIntent(alarmActivityPendingIntent, true);
Notification mNotification = mBuilder.build();
mNotificationManager.notify(alertSchedule.getIntentId(), mNotification);
This works as expected when only one alarm is set to fire at a specific time, however if two alarms are set to fire at a specific time the behavior changes.
I want the first fullScreenIntent to start its activity, then when that activity finishes, show the next one. I believe I want to build up a task stack, and push these alarm intents onto it. However this is all new to me.
Is it possible to group these notifications?
If you are using the full screen Intent feature, you don't need to use an IntentService or a Notification at all. Just have the AlarmManager start your Activity when it fires.
You don't want to build a task stack, that is all too complicated. If you have multiple alarms that can fire at the same time, you can have the AlarmManager start the same Activity each time. Set the launch mode of this Activity to singleTop (in the manifest), so that if the Activity is already showing when the alarm fires, it will not create another instance of the Activity on top of the existing one, but instead will deliver the Intent by calling onNewIntent() on the existing instance of the Activity. In onNewIntent() you can save the data (extras) of the Intent in a queue that will be processed when the user finishes the currently shown Activity. To do that, just override onBackPressed() so that when the user presses the BACK button to finish the current Activity, you can check if there are any additional alarms waiting in the queue. If there are none, you can just call super.onBackPressed() to finish the Activity. If there is anything in the queue, you can remove the first element in the queue and display that in your Activity. Keep doing that until the queue is empty.

Notification click behaviors depending on the state of the app

After a long search, I was not able to find exactly what I need.
I simply want : When a notification is displayed to the user, if the app is simply in background I want to reopen MainActivity. But if the app/activity has been killed, I want to restart the app completely.
My actual code :
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle(notification.getSubject())
.setContentText(notification.getMessage())
.setSound(Settings.System.DEFAULT_NOTIFICATION_URI);
mBuilder.setContentIntent(
PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class)
.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_UPDATE_CURRENT));
NotificationManager mNotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notif = mBuilder.build();
notif.flags = Notification.DEFAULT_VIBRATE | Notification.FLAG_AUTO_CANCEL;
Case which is not working actually is to restart the app if app or activity has been killed.
EDIT : By killed I mean the app has been closed in the app manager. Or we lost the focus and the activity is destroyed. In those cases I would like to fully restart the app.
I think you don't entirely understand how android functions. Whenever your program is needed, the program is started by android (See the Application class for an onCreate that you can override).
Whenever an activity is necessary it is (re)created or brought to the foreground.
That means that an activity restart does not necessarily imply a restart of the application. In practice, if the program was still in memory, then an application restart won't happen.
If you want to investigate this further
create an Application.onCreate method so you see whether your app is restarted or not.
trigger the notification
go to the android settings, application tab, and there select 'show cached processes'. Clear your process from the list.
tap the notification.
This should trigger a restart of the application. If this is indeed the problem then you cannot 'solve' it. Android decides when it will kill your application and when it removes it from memory.
The best solution then is to redesign your activity that whatever the application restart would trigger is also performed in the activity itself. Or so, without more detail what functionality you would like to see performed on an 'activity/application-restart' it is difficult to advice further on this matter.
I think you need to change your setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) value to setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT).
The reason is due to the way that FLAG_ACTIVITY_REORDER_TO_FRONT
works. When you use this flag, Android looks for an instance of the
desired activity in your activity stack, starting from the front of
the stack and scanning until it gets to the root/back of the stack. As
soon as it finds an instance of the specified activity, it brings that
one to the front (ie: if there are multiple instances of the specified
activity it will bring to the front the most recent instance).
Original I found here.
See android developer doc here.
I hope its help you.

Android service is frequently stopped and restarted

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.

Recommended method of starting a scheduled activity on start up?

Im trying to make an scheduled activity go off every hour or so, all working in the background.
Right now i have a BroadcastReceiver that picks up when the device is booted.
The BroadcastReceiver creates a PendingIntent to an activity (Called AlarmController) that creates has all necessary methods that i need for making the scheduled activity to go off.
How ever, this doesnt seem to work.
This is how my BroadcastReciever class onReceive{} looks like and is indentical to my main activity onCreate{}(Only for testing)
Intent intent = new Intent(serviceactivirt.this, AlarmController.class);
PendingIntent sender = PendingIntent.getActivity(serviceactivirt.this, 0, intent, 0);
try {
sender.send();
} catch (CanceledException e) {
Toast.makeText(getApplicationContext(), "FEJLSAN", Toast.LENGTH_LONG).show();
}
This actually works, except that my app crashes at launch, but the scheduled activity is working...
Any ideas? Is this "The way to do it" or is there a more recommended way?
Cheers!
Solution:
Instead of having a BroadcastReciever calling an Activity, i made the BroadcastReciever starting a Service. And changed my Activity to a Service, programmaticly and in manifest.
Works great!
Im trying to make an scheduled activity go off every hour or so, all working in the background.
Please allow users to configure other options, such as using a Notification, rather than being interrupted by an activity taking over the foreground.
Right now i have a BroadcastReceiver that picks up when the device is booted.
You would only need that to set up an AlarmManager schedule for your hourly events. Your PendingIntent for the AlarmManager could be one you obtain via getActivity().
How ever, this doesnt seem to work.
If you want to start an activity, call startActivity(). Do not create a PendingIntent, then immediately send() the PendingIntent.
Also, get rid of getApplicationContext() and simply use this.
except that my app crashes at launch
Use adb logcat, DDMS, or the DDMS perspective in Eclipse to examine LogCat and look at the stack trace associated with your crash.

Categories

Resources