olivierg
olivierg

Reputation: 10240

Resume application and stack from notification

I want to resume my app from a status bar notification in the exact same manner as when the user taps its icon in the launcher.

That is: I want the stack to be in the same state as it was before the user left it.

The problem when setting a pending intent on the notification is that it always targets a specific activity. I don't want this. I need to resume the application just as the launcher does.

So if the user is in activity A, I want to resume activity A. If he has launched activity B from activity A, then I want B to be displayed when the user taps the notification, and the stack to be restored so that A gets resumed when the user taps the back button in B.

There are couple of other questions of questions with similar titles, but none address my problem.

Upvotes: 75

Views: 37477

Answers (8)

coolcool1994
coolcool1994

Reputation: 3804

THE ULTIMATE SOLUTION: Notification to restore a task rather than a specific activity?

public class YourRootActivity extends Activity 
    {
        @Override
        protected void onCreate(Bundle savedInstanceState) 
        {
            super.onCreate(savedInstanceState);
    
            if (!isTaskRoot()) // checks if this root activity is at root, if not, we presented it from notification and we are resuming the app from previous open state
            {
                 val extras = intent.extras // do stuffs with extras.
                 finish();
                 return;
            }
             // OtherWise start the app as usual
        }
    }

Upvotes: 2

Thomas
Thomas

Reputation: 2458

For situations where you don't want / can't hard code the launcher activity this solution works

Intent i = getPackageManager()
    .getLaunchIntentForPackage(getPackageName())
    .setPackage(null)
    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, i, 0);

return new NotificationCompat.Builder(context)
        ...
        .setContentIntent(pendingIntent)
        .build();

The setPackage(null) part was key in my case since without it the app did not resume to previous task. I compared my intent with the intent from the Android launcher and noticed that pkg was not set there so that's how I came up with removing package name from the intent.

My particular situation was that the notification was created in a library so there I could not know what the launcher activity would be.

Upvotes: 49

GrAnd
GrAnd

Reputation: 10211

Just use the same intent filters as Android uses when it launches the app:

final Intent notificationIntent = new Intent(context, YourActivity.class);
notificationIntent.setAction(Intent.ACTION_MAIN);
notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

As the Intent you created to open your Activity from the notification bar is the same as Android used for launching your app, the previously opened Activity will be shown instead of creating a new one.

Upvotes: 173

Cezar Alexandru Vancea
Cezar Alexandru Vancea

Reputation: 580

<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.REORDER_TASKS" />

private void bringApplicationToForeground(){
    ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);

    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

      List<ActivityManager.AppTask> tasksList = am.getAppTasks();
      for (ActivityManager.AppTask task : tasksList){
        task.moveToFront();
      }
    }else{

      List<ActivityManager.RunningTaskInfo> tasksList = am.getRunningTasks(Integer.MAX_VALUE);
      if(!tasksList.isEmpty()){
        int nSize = tasksList.size();
        for(int i = 0; i < nSize;  i++){
          if(tasksList.get(i).topActivity.getPackageName().equals(getPackageName())){
            am.moveTaskToFront(tasksList.get(i).id, 0);
          }
        }
      }
    }
}

Upvotes: -1

Oguz Ozcan
Oguz Ozcan

Reputation: 1714

I also had the same problem and try to resolve the problem like @GrAnd's answer:

final Intent notificationIntent = new Intent(context,YourActivity.class);
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);

This works, no doubts about it but the problem is when you set your intent as ACTION_MAIN. Then you will not be able to set any bundle to the intent. I mean, your primitive data will not be received from the target activity because ACTION_MAIN can not contain any extra data.

Instead of this, you can just set your activities as singleTask and call your intent normally without setting ACTION_MAIN and receive the intent from onNewIntent() method of your target activity.

But beaware if you call, super.onNewIntent(intent); then a second instance of the activity will be created.

Upvotes: 4

H&#233;ctor William
H&#233;ctor William

Reputation: 796

Creating an activity and then set the categories and a respective flags... This was the way this worked for me, I had to do it this way cause I did it to support Api lvl 8

intent.addCategory(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setClass(this, YourActivity.class);

intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT|
                Intent.FLAG_ACTIVITY_SINGLE_TOP);

PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 
                   PendingIntent.FLAG_UPDATE_CURRENT);

and in the AndroidManifest

android:launchMode="singleTask"

So what made the trick was the Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT along with the line setted in the manifest.

Hope it helps to other people.

Upvotes: 4

Sher Ali
Sher Ali

Reputation: 5793

This is Very Simple open Your manifest file and set attribute Launch mode singleTop in your activity attribute

Upvotes: 0

auwall
auwall

Reputation: 341

There could be a more simple way, but you could store the data in the sqlite database and whenever you restart the app whatever states you have saved to the database you can retrieve and set your values to what they need to be at.

Upvotes: -4

Related Questions