Scenario:
App is in the background, main Activity is in onStop state. I receive a specific message, display a notification to the user, he clicks on it and I want to bring the app to the forwground and just resume the main Activity, without starting a new one.
I want the samw effect as you get when you click on a paused app in the recent tasks(it just resumes).
I assume that this has to do with setting the right flags on an Intent, but I couldn't find it.
Is it possible? Thanks.
The Notification just needs to contain a launch Intent to bring your app to the foreground in whatever state it was in:
PackageManager pm = context.getPackageManager();
Intent launchIntent = pm.getLaunchIntentForPackage(context.getPackageName());
PendingIntent pi = PendingIntent.getActivity(context, requestCode, launchIntent, 0);
Set pi as contentIntent on the Notification.
Related
I have implemented push notification for the app. When notification is tapped, How to start the application from splash screen if the app is already killed. I want to start from Splash screen if the app is already killed and start from Inside landing screen if the app is already in the background. How to handle this? Please help me.
Add this code to your create notification method:
Intent resultIntent = new Intent(this, SplashActivity.class);
resultIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
resultIntent.setAction(Intent.ACTION_MAIN);
resultIntent.addCategory(Intent.CATEGORY_LAUNCHER);
PendingIntent resultPendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
Play around with the intent flags [resultIntent.addFlags(/*intent flag here*/)], if you want to:
start from Splash screen if the app is already killed and start from
Inside landing screen if the app is already in the background.
Hope this helps!
Use pendingIntent to specify the action which should be performed once the user select the notification.
Example tutorial Here
I'm developing notifications in my app, and I'm having some issue with the pending intent that is driving me crazy.
Normal flow: My app has the launcher activity (Activity A, singleTop) which shows a Splash and then launches Activity B (singleTop too).
Notification:
When app is in background, I show a notification on the notification bar, which opens the launcher activity of my app when clicked, through a PendingIntent. This PendingIntent addresses to Activity A (singleTop). But in this scenario, instead of open Activity A, it brings to foreground the Activity B, but without calling onNewIntent() (onResume() is being called instead), so I can't retrieve the extras of the notification Intent and show the information, because this Activity B.getIntent() retrieves the old intent which opened the activity the first time.
Can any of you bring me some light on this issue, please?
This is how I set up the PendingIntent:
Intent notificationIntent = new Intent(context, SplashActivity.class);
notificationIntent.putExtra(StaticResources.EXTRA_NOTIFICATION_TYPE, "Notification");
notificationIntent.putExtra(StaticResources.EXTRA_NOTIFICATION_MESSAGE, "Message");
notificationIntent.putExtra(StaticResources.EXTRA_NOTIFICATION_TITLE, "title");
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
Edited:
Following the answer given by #Woodi_333, the code for creating the pending intent is as follow.
Intent notificationIntent = new Intent(context, SplashActivity.class);
notificationIntent.putExtra(StaticResources.EXTRA_NOTIFICATION_TYPE, "Notification");
notificationIntent.putExtra(StaticResources.EXTRA_NOTIFICATION_MESSAGE, "Message");
notificationIntent.putExtra(StaticResources.EXTRA_NOTIFICATION_TITLE, "title");
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
Some code would help but I can take a guess at what is causing this.
So it sounds like the Activity Stack before clicking the PendingIntent is A,B. When opening the PendingIntent, it closes B because of FLAG_ACTIVITY_CLEAR_TOP but leaves activity A alone so it remains running.
So onNewIntent won't run because A is still running, and the FLAG_ACTIVITY_SINGLE_TOP flag won't cause it to run as when the intent is fired, it is not on the top of the history stack.
You might want to combine it with FLAG_ACTIVITY_NEW_TASK as suggested in Documentation for FLAG_ACTIVITY_CLEAR_TOP
I'd also recommend looking at the flags you defined in the manifest to see if they are interfering with the flags of the Pending Intent, or add them to the activities so every time you launch them, they are obeying the same rules.
I use this code, inside a notification, so when the user taps the notification the MainActivity starts:
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);
If the user exits the app with the back button and taps a notification then main activity starts but if the user exit the app with the home button a new MainActivity starts over the first one. How can I detect if the MainActivity is loaded?
Thkx
You should add flags to your Intent to specify this behavior. Something like FLAG_ACTIVITY_CLEAR_TOP may be what you're looking for. This will finish any Activities on top of MainActivity (if any) and bring any existing instance to the foreground. If no instance is available, one will be created. Depending on your launchMode, you'll either get a callback to onNewIntent() (receiving the new Intent you provided) or the activity will be recreated with the new Intent.
Intent mainIntent = new Intent(this, MainActivity.class);
mainIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent.getActivity(this, 0, mainIntent, 0);
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
I am working on a task switcher, and already figured out the way to show list of apps and switch to the app when user presses my notification. My problem is, instead of resuming the app, like launcher does, my app just starts new instance (resets) the activity it's switching to.
Here's the code I'm using to set the Intent:
ComponentName componentName = taskInfo.topActivity;
String packageName = componentName.getPackageName();
/*Setting intent*/
Intent startApp = packageManager.getLaunchIntentForPackage(packageName);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, startApp, PendingIntent.FLAG_UPDATE_CURRENT);
childView.setOnClickPendingIntent(R.id.imageButton2, pendingIntent);
To be clear, I want the user to be able to got back to whatever he was doing in that app instead of starting it anew.