@@ -2336,7 +2336,7 @@ static void fireForegroundHandlers(OSNotificationController notificationControll
2336
2336
/**
2337
2337
* Method called when opening a notification
2338
2338
*/
2339
- static void handleNotificationOpen (final Activity context , final JSONArray data , final boolean fromAlert , @ Nullable final String notificationId ) {
2339
+ static void handleNotificationOpen (final Activity context , final JSONArray data , final boolean startLauncherActivity , @ Nullable final String notificationId ) {
2340
2340
// Delay call until remote params are set
2341
2341
if (taskRemoteController .shouldQueueTaskForInit (OSTaskRemoteController .HANDLE_NOTIFICATION_OPEN )) {
2342
2342
logger .error ("Waiting for remote params. " +
@@ -2346,7 +2346,7 @@ static void handleNotificationOpen(final Activity context, final JSONArray data,
2346
2346
public void run () {
2347
2347
if (appContext != null ) {
2348
2348
logger .debug ("Running " + OSTaskRemoteController .HANDLE_NOTIFICATION_OPEN + " operation from pending queue." );
2349
- handleNotificationOpen (context , data , fromAlert , notificationId );
2349
+ handleNotificationOpen (context , data , startLauncherActivity , notificationId );
2350
2350
}
2351
2351
}
2352
2352
});
@@ -2364,11 +2364,41 @@ public void run() {
2364
2364
2365
2365
if (shouldInitDirectSessionFromNotificationOpen (context , data )) {
2366
2366
applicationOpenedByNotification (notificationId );
2367
+
2368
+ if (startLauncherActivity ) {
2369
+ // Start activity with an activity trampolining
2370
+ startOrResumeApp (context );
2371
+ }
2367
2372
}
2368
2373
2369
2374
runNotificationOpenedCallback (data );
2370
2375
}
2371
2376
2377
+ // Reverse activity trampolining is used for most notifications.
2378
+ // This method is only used if the push provider does support it.
2379
+ // This opens the app in the same way an Android home screen launcher does.
2380
+ // This means we expect the following behavior:
2381
+ // 1. Starts the Activity defined in the app's AndroidManifest.xml as "android.intent.action.MAIN"
2382
+ // 2. If the app is already running, instead the last activity will be resumed
2383
+ // 3. If the app is not running (due to being push out of memory), the last activity will be resumed
2384
+ // 4. If the app is no longer in the recent apps list, it is not resumed, same as #1 above.
2385
+ // - App is removed from the recent app's list if it is swiped away or "clear all" is pressed.
2386
+ static boolean startOrResumeApp (@ NonNull Activity activity ) {
2387
+ Intent launchIntent = activity .getPackageManager ().getLaunchIntentForPackage (activity .getPackageName ());
2388
+ logger .debug ("startOrResumeApp from context: " + activity + " isRoot: " + activity .isTaskRoot () + " with launchIntent: " + launchIntent );
2389
+
2390
+ // Not all apps have a launcher intent, such as one that only provides a homescreen widget
2391
+ if (launchIntent == null )
2392
+ return false ;
2393
+ // Removing package from the intent, this treats the app as if it was started externally.
2394
+ // This gives us the resume app behavior noted above.
2395
+ // Android 11 no longer requires nulling this out to get this behavior.
2396
+ launchIntent .setPackage (null );
2397
+
2398
+ activity .startActivity (launchIntent );
2399
+ return true ;
2400
+ }
2401
+
2372
2402
private static boolean shouldInitDirectSessionFromNotificationOpen (Activity context , final JSONArray data ) {
2373
2403
if (inForeground ) {
2374
2404
return false ;
0 commit comments