singleTask and singleInstance not respected when using PendingIntent? - android

I have an activity with launchMode set to singleTask:
<activity
android:name="com.blah.blah.MyActivity"
android:launchMode="singleTask">
</activity>
I have an ongoing notification with a PendingIntent that launches that activity:
Intent activityIntent = new Intent( this,
MyActivity.class );
TaskStackBuilder stackBuilder = TaskStackBuilder.create( this );
stackBuilder.addParentStack( MyActivity.class );
stackBuilder.addNextIntent( activityIntent );
PendingIntent resultingActivityPendingIntent = stackBuilder.getPendingIntent( REQUEST_CODE,
PendingIntent.FLAG_UPDATE_CURRENT );
...
m_notificationBuilder.setContentIntent( resultingActivityPendingIntent );
startForeground( ONGOING_NOTIFICATION_ID,
m_notificationBuilder.build() );
When I am interacting with an existing MyActivity, then I hit Home and restart MyActivity via the launcher, MyActivity's onNewIntent() gets called as expected.
The problem is that when I am interacting with an existing MyActivity, and I click on the ongoing notification, a new MyActivity is created via onCreate(), and the existing one is destroyed via onDestroy(). I expected that MyActivity's onNewIntent() would be called instead. Why doesn't this happen?
I have tried these answers without success:
Intent - if activity is running, bring it to front, else start a new one (from notification)
How to make notification resume and not recreate activity?
FLAG_ACTIVITY_REORDER_TO_FRONT ignored (in this case the existing instance is not destroyed when the notification is clicked)

Your problem is due to the use of TaskStackBuilder. This code is causing your problem:
Intent activityIntent = new Intent( this,
MyActivity.class );
TaskStackBuilder stackBuilder = TaskStackBuilder.create( this );
stackBuilder.addParentStack( MyActivity.class );
stackBuilder.addNextIntent( activityIntent );
PendingIntent resultingActivityPendingIntent =
stackBuilder.getPendingIntent(REQUEST_CODE,
PendingIntent.FLAG_UPDATE_CURRENT );
When you use TaskStackBuilder this way, it sets additional flags in the generated Intents that cause the task to be reset (all Activities in the task are destroyed) before your Activity gets launched.
Instead use:
Intent activityIntent = new Intent( this,
MyActivity.class );
PendingIntent resultingActivityPendingIntent =
PendingIntent.getActivity(this, REQUEST_CODE,
activityIntent, PendingIntent.FLAG_UPDATE_CURRENT );

Related

Set different activities for pending intent of notification

I am currently facing the problem of setting pending action for two different activities to notification.
I have a ParentActivity and a ChildActivity. I want open ChildActivity on notification click if currently it is running or paused, otherwise start ParentActivity.
I tried this :
.........
Intent resultIntent = new Intent(this, ChildActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(ParentActivity.class);
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
.............
Above is not working for me. Everytime ChildActivity is starting on notification click.
And also as Faruk answered, I dont want this. Creating a notification's pending intent by checking ChildActivity's current state will not work.
Suppose notification created when ChildActivity was running but after creating the notification, user killed the app. So after killing the app, If user will click on notification then ChildActivity will start. I don't want that. I want if ChildActivity is not running or paused then ParentActivity should be started.
How can I achieve this?
Please help.
While there may be several ways to achieve this, following is the one I can think of.
First, you should get whether ChildActivity is active or not, through this link
Check whether activity is active
Store this in some variable childActive, then you can initialize different notificationIntents checking the value without using task TaskStackBuilder.
For example;
Intent notificationIntent = null;
if(childActive)
notificationIntent = new Intent(context, ChildActivity.class);
else
notificationIntent = new Intent(context, ParentActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(context,
0, notificationIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
Have your Notification launch a simple dispatch Activity. This Activity does the following in onCreate():
super.onCreate(...);
if (ChildActivity.running) {
// ChildActivity is running, so redirect to it
Intent childIntent = new Intent(this, ChildActivity.class);
// Add necessary flags, maybe FLAG_ACTIVITY_CLEAR_TOP, it depends what the rest of your app looks like
childIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(childIntent);
} else {
// Child is not running, so redirect to parent
Intent parentIntent = new Intent(this, ParentIntent.class);
// Add necessary flags, maybe FLAG_ACTIVITY_CLEAR_TOP, it depends what the rest of your app looks like
parentIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(parentIntent);
}
finish();
In ChildActivity do this:
public static boolean running; // Set when this Activity is active
In ChildActivity.onCreate() add this:
running = true;
In ChildActivity.onDestroy() add this:
running = false;

Activity with launchMode singleTop or singleTask is always recreated

The MainActivity in my app has a launchMode of singleTop defined in the manifest file. Whenever I click a notification my MainActivity is re-created and the old instance is destroyed. MainActivity is visible and in the foreground when the notification is clicked, so I would assume the intent would be passed to the current instance's onNewIntent(), but this never happens. Here is the intent I create:
Intent resultIntent = new Intent(App.getInstance(), MainActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(App.getInstance());
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = PendingIntent.getActivity(App.getInstance(), 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
I sometimes add the FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_SINGLE_TOP to the intent like so:
resultIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
I have also tried using the singleTask launchMode also with those flags and the same behavior has happened. Could someone lend some insight on this behavior?
You don't need to create a new TaskStackBuilder. Try intent which acts like you want to restart the application, but singleTop will keep it from doing so:
Intent resultIntent = new Intent(App.getInstance(), MainActivity.class);
resultIntent.setAction(Intent.ACTION_MAIN);
resultIntent.addCategory(Intent.CATEGORY_LAUNCHER);
PendingIntent resultPendingIntent = PendingIntent.getActivity(App.getInstance(), 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);

Android start the same activity but close previous one

I am trying to start my activity from the notification and it is working but instead of starting the same activity, another (copy) of my activity gets launched when i exit from it I find another copy of the activity beneath it.
NotificationCompat.Builder b = new NotificationCompat.Builder(this);
....
Intent intent = new Intent(this, MyActivity.class);
intent.putExtra("item", currentObj);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0);
....
b.setContentIntent(pIntent);
how can I fix this ??
you have to use TaskStackBuilder and add its parent
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(resultIntent);
and you have add it in the notification
stackBuilder.addParentStack(MainActivity.class);
What it does is simple it just says android about the parent of the present class you have opened! This should slove your problem. I hope this is helpful. Thankyou
You can call finish(); before b.setContentIntent(pIntent);.
There is a flag you can set that starts the same activity instead of a new one each time:
Intent intent = new Intent(this, MyActivity.class);
intent.putExtra("item", currentObj);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
You can add this line to your Activity inside manifest to prevent from loading the same activity multiple times
android:launchMode = "singleInstance"
OR
Flag the intent before starting Activity like this
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

Sending parameters from a notification to a different activity?

I have a follow on question to the question answered here: How to send parameters from a notification-click to an activity?
So, I have 3 activities, A, B, and C. An alarm (timer) starts when the user gets to activity C. After X amount of time, a notification appears in the status bar. Below is how I launch the notification. "MainActivity.class" is activity A. However, launching the notification in this way restarts the application in whatever activity the user was in when the closed it. So, if they were in activity C when the app closed and they click on the notification, the app will resume to activity C.
Intent notificationIntent = new Intent( this, MainActivity.class );
notificationIntent.setAction( Intent.ACTION_MAIN );
notificationIntent.addCategory( Intent.CATEGORY_LAUNCHER );
notificationIntent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED );
notificationIntent.putExtra( NotifyService.NOTIFICATION_INTENT, true );
PendingIntent contentIntent = PendingIntent.getActivity( this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT );
Notification notification = new Notification.Builder( this )
.setContentTitle( title )
.setContentText( text )
.setTicker( ticker )
.setSmallIcon( R.drawable.ic_launcher )
.setWhen( time )
.setContentIntent( contentIntent )
.setAutoCancel( true )
.setDefaults( Notification.DEFAULT_ALL )
.build();
I have this in the manifest for activities A, B, and C: android:launchMode="singleTop". I also have the following code in each activity.
#Override
public void onNewIntent( Intent intent )
{
super.onNewIntent( intent );
Bundle extras = intent.getExtras();
if( extras != null )
{
Boolean startedFromNotification = extras.getBoolean( NotifyService.NOTIFICATION_INTENT );
if( startedFromNotification )
{
// Do something
}
}
}
Now, if the user was in activity A when they closed the app, then onNewIntent gets called in that activity when they click on the notification (working as expected). But, if they were in activity B or C, not only does onNewIntent in those activities not get called, but the extra I put in there (NotifyService.NOTIFICATION_INTENT) is also missing.
Is there anyway to pass the notification intent extras to the app when it resumes to activity B or C?
I was lead to an answer via this question: FLAG_ACTIVITY_NEW_TASK not behaving as expected when used in PendingIntent
First, I changed this line:
Intent notificationIntent = new Intent( this, MainActivity.class );
To:
Intent notificationIntent = new Intent( this, NotificationActivity.class );
I made NotificationActivity.class a placeholder activity that will let other activities know when the app is being resumed from a notification. These lines of code were removed:
notificationIntent.setAction( Intent.ACTION_MAIN );
notificationIntent.addCategory( Intent.CATEGORY_LAUNCHER );
notificationIntent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED );
notificationIntent.putExtra( NotifyService.NOTIFICATION_INTENT, true );
And, this line:
PendingIntent contentIntent = PendingIntent.getActivity( this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT );
Was changed to:
PendingIntent pendingIntent = PendingIntent.getActivity( this, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT );
In the onCreate() method of NotificationActivity, I added these lines to the bottom:
STARTED_FROM_NOTIFICATION = true;
finish();
Where STARTED_FROM_NOTIFICATION is in a common source file. Then, in each activity in the onStart() method:
if( STARTED_FROM_NOTIFICATION == true )
{
STARTED_FROM_NOTIFICATION = false;
// Do something
}
I also removed android:launchMode="singleTop" from all activities.
Using this method, the NotificationActivity will be placed on top of the existing stack of activities, but will be finished before it is displayed. After it is finished, onStart() for the activity below it will be called and operation works as desired.

Launching an activity from notification

I am trying to launch an activity from the notification.
I have activity A. The activity A is launched from clicking on the notification. Once the activity A is launched, I like to get back to MainActivity upon pressing the phone's back button. To happen like that I implement as follow. The code is implemented in the BroadcastReceiver. I am having the compilation error at this line Intent resultIntent = new Intent(MainActivity.this, theClass); Because MainActivity.this is not valid in the BroadcastReceiver class. How can I make it correct?
Class theClass = Class.forName("sg.SanThit.TrackMe.NotificationListActivity");
Intent resultIntent = new Intent(MainActivity.this, theClass);
resultIntent.putExtra("MOBILENUMBER", tel);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(MainActivity.this);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(theClass);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);

Categories

Resources