73

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.

olivierg
  • 10,200
  • 4
  • 30
  • 33
  • possible duplicates: http://stackoverflow.com/questions/3356095/how-to-bring-android-existing-activity-to-front-via-notification, http://stackoverflow.com/questions/4047683/android-how-to-resume-an-app-from-a-notification – Philipp Feb 17 '13 at 04:13
  • Does this answer your question? [How to bring Android existing activity to front via notification](https://stackoverflow.com/questions/3356095/how-to-bring-android-existing-activity-to-front-via-notification) – Delwyn Pinto Feb 12 '20 at 08:02

8 Answers8

171

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.

David Wasser
  • 93,459
  • 16
  • 209
  • 274
GrAnd
  • 10,141
  • 3
  • 31
  • 43
  • Thanks! Works great. Tested on Moto Droid, X10 Mini and Samsung S. – olivierg Mar 31 '11 at 17:15
  • 3
    Just a question: what if a particular/alternative launcher use a slightly different intent? Maybe with some other extras or categories.. Do you think that I should cache the original intent my app was started with (as retrieved by Activity.getIntent()), and use that as-is to create my pending intent? – olivierg Mar 31 '11 at 18:37
  • Works as what I expected. Thanks so much. – sunghun Oct 30 '12 at 10:56
  • 2
    I worked for me, I had Two activate splash and mainactivity, after modifying my code with the above code, it resumes mainactive without starting new activity. thank you soo much.. – Sai Nov 05 '13 at 09:00
  • How to open App in previous state @ – Pratik Butani Jan 02 '14 at 12:33
  • Best solution so far. Resumes the app, no matter how many layers of activity deep you're in. – mbmc Apr 27 '14 at 19:40
  • You've saved my life, thank you. I can confirm it does exactly the same thing as if I had launched the app from home screen. – Aron Lorincz Jun 12 '14 at 13:07
  • 7
    Its not working for me any help please. I am trying with nexus 5. – Kantesh Sep 11 '14 at 09:12
  • It's working, but randomly. Sometimes it works and sometimes the activity is restarted! – DarkLeafyGreen Oct 14 '15 at 13:25
  • I found that this did not work with Android 5.0.2. It would push a new activity on top of the current one, if the top activity is not the target one. – awy Dec 29 '15 at 14:09
  • 2
    Trying with lollipop and it doesnt work. Just opens up a new 'YourActivity' – Murphybro2 Jan 25 '16 at 10:57
  • It really works, but after clicking of notification, it disappears from bar, what do I do to keep it there? – Parissa Kalaee Oct 26 '16 at 10:01
  • For all those saying it doesn't work on **Lollipop**, yes it does. Just make sure you don't add the flag `Intent.FLAG_ACTIVITY_CLEAR_TOP` (it might come from some tutorial you copied) – Alaa M. Nov 11 '16 at 10:45
  • 1
    Is there any way to do this and also pass new extras in intent? – Gokhan Arik Jan 08 '18 at 17:32
  • 1
    Wow. After hours of tweaking flags, this solution finally worked. Thanks a bunch! – farthVader Jan 26 '18 at 16:47
  • 1
    Worked without last line (not needed) in Android 4.3 (18) and 6.0, 6.0.1 (23)! Using with VS 2017 v.15.5.4, Xamarin v.4.8.0.757. The only solution to solve exactly same as OP's problem. Looked at 15+ similar questions before finding this one. – Astrogator Apr 09 '18 at 21:15
  • Correction: Works with flags (last line) changed to ActivityFlags.SingleTop or Intent.FLAG_ACTIVITY_SINGLE_TOP. – Astrogator Apr 09 '18 at 21:46
  • this works but in order to pass in extras data this only other solution works: https://stackoverflow.com/questions/6575730/notification-to-restore-a-task-rather-than-a-specific-activity – coolcool1994 Aug 20 '20 at 09:51
  • @GrAnd Can you link to where you found this code? Is it in the ASOP? I notice it doesn't use `setPackage` or `setClassName` to ensure it is opening the correct app. Android allows you to have two different Android apps (different package name of course) but with the same exact Activity name w/ namespace and it won't know which one to use. – jkasten Feb 04 '21 at 02:16
49

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.

Thomas
  • 2,368
  • 20
  • 22
  • Works perfectly. But in my case I need to pass some data, it is working fine where application completely quit and able to get data in onCreate - Intent, whereas I'm not able to get data from Intent where application is running in background.Could you please – Prat Oct 04 '18 at 06:43
  • it looks like that only working solution but what for you set FLAG_ACTIVITY_RESET_TASK_IF_NEEDED? – Emil Dec 11 '18 at 11:26
  • Thank you, Thomas. You saved me after hours of struggle. – Hristo Stoyanov Jan 31 '19 at 11:31
  • @Prat for app running, you will get data in onNewIntent() - more info https://developer.android.com/reference/android/app/Activity#onNewIntent(android.content.Intent) – Smeet Jul 04 '19 at 06:33
  • 1
    Finally an answer that works as expected, it works perfectly! Specifying the activity doesn't make sense anyway, so even if those other solutions work, this one is much clearer! – P Kuijpers Mar 26 '20 at 16:30
  • Sometimes it doesn't work. I have two different activities, A and B. I wait for Firebase Push Notification and show ongoing notification after it comes. By notification click I show activity B and show at the same time other notification. That notification sould do exactly the same action as author of this topic asked, e.g. just resume app from the last activity. In case if activity A was launched before I showed activity B it works great. But if I show B without previously showed A then after notification click I see activity A istead of activity B. – Ivan Syabro May 06 '20 at 08:24
  • Top answer or any other answers all don't work for me. This is the only one that works! – Bruce Oct 01 '20 at 07:40
4

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.

Oguz Ozcan
  • 1,694
  • 19
  • 26
3

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.

Héctor William
  • 756
  • 6
  • 24
  • `Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT` does nothing, `android:launchMode="singleTask"` is not recommended, activity won't ever be recreated even during orientation and other config changes – user924 Sep 13 '20 at 09:30
  • Did you try It with API lvl 8? Its been like 6 years, I guess a lot have changed. So rude to mark it as not useful btw. – Héctor William Sep 14 '20 at 18:19
1

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
        }
    }
coolcool1994
  • 3,704
  • 4
  • 39
  • 43
0

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

Sher Ali
  • 5,513
  • 2
  • 27
  • 29
  • What API did you test this on? It doesn't seem to work on API 23. Pressing 'back' then clicking the notification launches a 2nd instance of the activity – behelit May 25 '16 at 06:40
-1
<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);
          }
        }
      }
    }
}
-4

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.

auwall
  • 331
  • 3
  • 9