Android 12 - About Correspondence to notification trampoline - android

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

Related

Notification with button that upon click take an action without opening activity

I am trying to create a notification where I add button to it that would basically do some action. I know I can do the following
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(con)
.setSmallIcon(image)
.setContentTitle("title")
.addAction(icon, title, intent)
My questions are:
1) Is adding button supported in API 5.0+ ONLY or also in 4.x? I read different answers about it
2) The action seems to be associated with opening an activity. Is there away I can have it so when you click on a button it takes an action without having to open the activity (Either through broadcast receiver or some other way)? As far as I know Intent opens activities.
Thank you so much
It will work in Android 4.1 and later. See official doc.
If you want to do action with out any UI update(i.e., showing any activity), I suggest send a pending intent(which will trigger a broadcast receiver) as a parameter for notification action
i) Create a BroadcastReceiver named MyBroadcastReceiver
ii) Add your action in BroadcastReceiver's onReceive method
iii) Create a PendingIntent
Intent mIntent = new Intent(this,MyBroadcastReceiver.class);
PendingIntent mPendingIntent = PendingIntent.getBroadcast(this, 0, mIntent , 0);
iv) Add it to Notification
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(con)
.setSmallIcon(image)
.setContentTitle("title")
.addAction(icon, title, mPendingIntent)
1) Is adding button supported in API 5.0+ ONLY or also in 4.x?
It will work in Android 4.1 and later. See official doc.
2)...As far as I know Intent opens activities.
Yes, you can use BroadcastReceiver or Service for executing logic that doesn't involve UI. First of all, you can build intent to launch activity, broadcast receiver, or service. Secondly, the third argument of NoticiationCompat.Builder#addAction is PendingIntent, not an Intent. You can use PendingIntent.getService to create an PendingIntent for service, for instance.
http://developer.android.com/reference/android/app/PendingIntent.html#getService(android.content.Context, int, android.content.Intent, int)

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.

How to start an app the same way Android Launcher does (resume)

There are a lot of questions/answers about how to start an application from within your application in Android. But those solutions do not produce the same flow as if an icon was tapped in Android launcher.
For example, I do this (this is used with notifications):
intent = context.getPackageManager().getLaunchIntentForPackage("com.test.startup");
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
pendingIntent = PendingIntent.getActivity(context, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
Then when I tap on notification the app is started, however, it is started somewhat differently than when I tap the icon in the App drawer. Specifically: with this approach my main Activity is always created (i.e. onCreate() then onResume() is called). However, if application was already started and then put in background, then starting it from Launcher will only cause onResume() of currently shown activity to be called (not onCreate() on the main one). Is there a way to trigger the same resume flow programmatically from within my app?
To summarize the task: when user taps on notification I need my app to be either started (if it's not already), or brought to the foreground in its current state (if it's in background) and have some data passed to it. The app will then take care of handling/rendering that data.
Your app is behaving the way it supposed to. Even if you try the launch the app from App drawer it will call the same callback. You have to understand the lifecycle. As your activity is in the background onCreate will not get called. But for the handling the data from the notification intent you should utilize callback method OnNewIntent() in activity. You should override this method and extract the data the from the new intent and should update UI. After onNewIntent onresume will be called.
I hope this solves your problem.
Here is my onPause code which works the way you expected i.e when user clicks on the notification it doesnt call onCreate again:
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
intent = new Intent(getApplicationContext(), PlayerActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP| Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pIntent = PendingIntent.getActivity(getBaseContext(), 0, intent,0);
NotificationCompat.Builder noti =
new NotificationCompat.Builder(this)
.setSmallIcon(android.R.drawable.ic_media_play)
.setContentTitle("Nepali Music And more")
.setContentText("Playing");
noti.setContentIntent(pIntent);
noti.setAutoCancel(true);
noti.setOngoing(true);
Notification notification = noti.getNotification();
notificationManager.notify(1, notification);
Focus mainly on the intent flags
You want to use the intent flags Intent.FLAG_ACTIVITY_CLEAR_TOP to find your activity and clear the stack above it. You also need the Intent.FLAG_ACTIVITY_SINGLE_TOP flag to prevent your activity from being recreated (to resume).
The Intent.FLAG_ACTIVITY_SINGLE_TOP is necessary since by default, the launch mode is "standard" which lets you create multiple instances of your activity. If you were to set your launch mode to SingleTop, then this flag own't be necessary

Android startForeground notification disappears

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

Change notification intent in Android

I have a service that shows a notification that I wish that will be able to go to a specific activity of my app each time the user presses on it. Usually it would be the last one that the user has shown, but not always.
If the activity was started before, it should return to it, and if not, it should open it inside of the app's task, adding it to the activities tasks.
In addition, on some cases according to the service's logic, I wish to change the notification's intent so that it will target a different activity.
How do i do that? Is it possible without creating a new notification and dismissing the previous one? Is it also possible without creating a new task or an instance of an activity?
No it wouldn't be possible to change the Activity once you have sent the notification.
You can start an Activity on your task stack that is not a problem, check out the notification service in the tutorial here:
http://blog.blundell-apps.com/notification-for-a-user-chosen-time/
You have to set a pending intent on the notification:
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, SecondActivity.class), 0);
// Set the info for the view that shows in the notification panel.
notification.setLatestEventInfo(this, title, text, contentIntent);
You can see the pending intent takes a normal intent "new Intent(this, SecondActivity.class" so if you want specific behaviour (like bringing to the top instead of starting a new activity. Add the flags like you would normally to this intent. i.e. FLAG_ACTIVITY_REORDER_TO_FRONT (something like that)
Since platform version 11, you can build a notification using Notification.Builder. The v4 support library has an equivalent class NotificationCompat.Builder.
You can't change the Activity once you've sent the notification, but you can update the notification with a new Intent. When you create the PendingIntent, use the flag FLAG_CANCEL_CURRENT. When you send the new notification, use the ID of the existing notification when you call NotificationManager.notify().
Also, you should be careful how you start your app. The Status Bar Notifications guide tells you how to set up the back stack.

Categories

Resources