8

I have observed several similar questions but they couldn`t help me. I need to display last activity when user click notification. Here is my code:

NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(YourService.this)
        .setContentTitle(getResources().getText(R.string.app_name))
        .setContentText(getServiceStateDescription(YourService.this))
        .setSmallIcon(iconId)
        .setWhen(System.currentTimeMillis());

Intent nIntent = getPreviousIntent();
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack
stackBuilder.addParentStack(MainActivity_.class);
stackBuilder.addNextIntent(nIntent);
PendingIntent pendingIntent =
        stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
notificationBuilder.setContentIntent(pendingIntent);

startForeground(ContextConstants.LAUNCHER_SERVICE_NOTE_ID, notificationBuilder.build());


private Intent getPreviousIntent() {
Intent newIntent = null;
final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    final List<ActivityManager.AppTask> recentTaskInfos = activityManager.getAppTasks();
    if (!recentTaskInfos.isEmpty()) {
        for (ActivityManager.AppTask appTaskTaskInfo: recentTaskInfos) {
            if (appTaskTaskInfo.getTaskInfo().baseIntent.getComponent().getPackageName().equals(ContextConstants.PACKAGE_NAME)) {
                newIntent = appTaskTaskInfo.getTaskInfo().baseIntent;
                newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            }
        }
    }
} else {
    final List<ActivityManager.RecentTaskInfo> recentTaskInfos = activityManager.getRecentTasks(1024, 0);
    if (!recentTaskInfos.isEmpty()) {
        for (ActivityManager.RecentTaskInfo recentTaskInfo: recentTaskInfos) {
            if (recentTaskInfo.baseIntent.getComponent().getPackageName().equals(ContextConstants.PACKAGE_NAME)) {
                newIntent = recentTaskInfo.baseIntent;
                newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            }
        }
    }
}
if (newIntent == null) newIntent = new Intent();
return newIntent;

}

Second point is that if i used deprecated metods in order to build notification, displaying last activity works great as i wanted here is code:

Notification note = new Notification(iconId,
            getResources().getText(R.string.serviceStarted),
            System.currentTimeMillis());
    note.flags |= Notification.FLAG_ONGOING_EVENT;
    note.flags |= Notification.FLAG_NO_CLEAR;

    Intent nIntent = new Intent();
    nIntent = getPreviousIntent(nIntent);
    PendingIntent pi = PendingIntent.getActivity(this, 0, nIntent, 0);
    note.setLatestEventInfo(this,
            getResources().getText(R.string.app_name), getServiceStateDescription(YourService.this), pi);

    startForeground(ContextConstants.LAUNCHER_SERVICE_NOTE_ID, note);

But i don't want use deprecated metods anymore, that's why i'm here explaining. Thanks in advance!

And i've seen this doc as well.

Here is my manifest:

<?xml version="1.0" encoding="utf-8"?>

<permission android:name="com.my.package.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="com.my.package.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.GET_TASKS"/>

<application
    android:name=".MyApplication"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/Theme.AppCompat.Light">
    <activity android:name=".activity.StartingActivity_"  android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity
        android:name=".activity.MainActivity_"
        android:configChanges="orientation|screenSize">
    </activity>
    <activity
        android:name=".activity.ComposeEmailActivity_"
        android:configChanges="orientation|screenSize"
        android:parentActivityName=".activity.MainActivity_">
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value=".activity.MainActivity_" />
    </activity>
    <activity
        android:name=".activity.EditAccountActivity_"
        android:configChanges="orientation|screenSize"
        android:parentActivityName=".activity.MainActivity_">
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value=".activity.MainActivity_" />
    </activity>               

    <!--android:process=":remote" is for working in background-->
    <service android:enabled="true" android:name=".service.YourService"/>       

</application>

nAkhmedov
  • 3,522
  • 4
  • 37
  • 72
  • Do you just want to bring your application to the foreground in whatever state it was in when it went to the background? – David Wasser Jul 19 '15 at 20:53

1 Answers1

13

Your problem isn't with the methods you are using to build the Notification. Your problem is your use of TaskStackBuilder. Using this class performs a lot of hidden magic behind the scenes and it makes a lot of assumptions about how your want the app to behave. Unfortunately, these assumptions are mostly wrong :-(

If you just want to bring your application to the foreground in whatever state it was in when it went to the background, you don't want to use TaskStakBuilder and you also don't have to use all those nasty ActivityManager methods. Just do this:

NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(YourService.this)
    .setContentTitle(getResources().getText(R.string.app_name))
    .setContentText(getServiceStateDescription(YourService.this))
    .setSmallIcon(iconId)
    .setWhen(System.currentTimeMillis());

Intent nIntent = getPackageManager().
        getLaunchIntentForPackage(ContextConstants.PACKAGE_NAME);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, nIntent,
    PendingIntent.FLAG_UPDATE_CURRENT);
notificationBuilder.setContentIntent(pendingIntent);

startForeground(ContextConstants.LAUNCHER_SERVICE_NOTE_ID,
    notificationBuilder.build());
David Wasser
  • 93,459
  • 16
  • 209
  • 274
  • 1
    Hi! Thank you _@David Wasser_ for quickly reply, but it opens launcher activity always. – nAkhmedov Jul 20 '15 at 10:59
  • Also, how are you starting the app for the first time? From the installer or from an IDE or by clicking on the app icon from the HOME screen? – David Wasser Jul 20 '15 at 11:53
  • I have launched debug apk from android studio. – nAkhmedov Jul 21 '15 at 05:34
  • Launcher activity is StartingActivity_ on me, that`s why always it opens by tapping notification. – nAkhmedov Jul 21 '15 at 05:36
  • 6
    There is a nasty Android bug that you are probably seeing. Please try the following: Do not launch your App from Android Studio. Just deploy the app on the phone (or emulator) and then start it manually by tapping the app icon from the HOME screen. Then see if your notification always opens the launcher Activity. – David Wasser Jul 21 '15 at 15:52
  • 3
    Glad to help. See http://stackoverflow.com/a/16447508/769265 for more details about the bug. – David Wasser Jul 22 '15 at 09:25
  • 1
    How can we resume existing application? by above code it launch every time new application even application is in background. – Vishal Patoliya ツ Aug 10 '17 at 10:04
  • @ScottyB please don't suggest using `singleTask` launch mode! This is not the correct solution. It creates a lot more problems than it solves. Standard Android behaviour, when calling `startActivity()` with a "launch Intent" retrieved from the `PackageManager` , is to bring the existing task to the foreground **without creating a new instance of the `Activity`**. If you are seeing multiple instances of the `Activity` there is something else wrong. Special launch modes should hardly ever be used (unless you are building a HOME-screen replacement) – David Wasser Apr 26 '18 at 18:14
  • Thanks @DavidWasser. I didn't realize that. (I deleted my comment) I had just read a similar question at https://stackoverflow.com/questions/19163367/resume-an-activity-when-clicked-on-a-notification and saw a similar answer! – ScottyB Apr 26 '18 at 18:26
  • @VishalPatoliyaツdid you find a solution? – JCarlosR Sep 27 '18 at 22:20