From e1bf7fde108661899a5490f4fc5125d040e0206f Mon Sep 17 00:00:00 2001 From: Jeasmine Nahui Date: Thu, 10 Feb 2022 13:38:48 -0300 Subject: [PATCH 1/2] Fix HMS Activity trampolining * HMS notification with Message type "Message" won't trigger activity trampolining logic * Start application from NotificationOpenedActivityHMS --- .../NotificationOpenedProcessor.java | 2 +- .../NotificationPayloadProcessorHMS.java | 2 +- .../main/java/com/onesignal/OneSignal.java | 36 +++++++++++++++++-- .../OneSignalPackagePrivateHelper.java | 4 +-- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/NotificationOpenedProcessor.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/NotificationOpenedProcessor.java index afdafd571b..756fa8f593 100644 --- a/OneSignalSDK/onesignal/src/main/java/com/onesignal/NotificationOpenedProcessor.java +++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/NotificationOpenedProcessor.java @@ -109,7 +109,7 @@ static void processIntent(Context context, Intent intent) { if (!(context instanceof Activity)) OneSignal.onesignalLog(OneSignal.LOG_LEVEL.ERROR, "NotificationOpenedProcessor processIntent from an non Activity context: " + context); else OneSignal.handleNotificationOpen((Activity) context, intentExtras.getDataArray(), - intent.getBooleanExtra("from_alert", false), OSNotificationFormatHelper.getOSNotificationIdFromJson(intentExtras.getJsonData())); + false, OSNotificationFormatHelper.getOSNotificationIdFromJson(intentExtras.getJsonData())); } } diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/NotificationPayloadProcessorHMS.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/NotificationPayloadProcessorHMS.java index 34a83b7f8f..d47289c557 100644 --- a/OneSignalSDK/onesignal/src/main/java/com/onesignal/NotificationPayloadProcessorHMS.java +++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/NotificationPayloadProcessorHMS.java @@ -68,7 +68,7 @@ private static void handleProcessJsonOpenData(@NonNull Activity activity, @NonNu OneSignal.handleNotificationOpen( activity, new JSONArray().put(jsonData), - false, + true, OSNotificationFormatHelper.getOSNotificationIdFromJson(jsonData) ); } diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignal.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignal.java index ff045ef0dc..32176dbf17 100644 --- a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignal.java +++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignal.java @@ -2336,7 +2336,7 @@ static void fireForegroundHandlers(OSNotificationController notificationControll /** * Method called when opening a notification */ - static void handleNotificationOpen(final Activity context, final JSONArray data, final boolean fromAlert, @Nullable final String notificationId) { + static void handleNotificationOpen(final Activity context, final JSONArray data, final boolean fromHMSMessage, @Nullable final String notificationId) { // Delay call until remote params are set if (taskRemoteController.shouldQueueTaskForInit(OSTaskRemoteController.HANDLE_NOTIFICATION_OPEN)) { logger.error("Waiting for remote params. " + @@ -2346,7 +2346,7 @@ static void handleNotificationOpen(final Activity context, final JSONArray data, public void run() { if (appContext != null) { logger.debug("Running " + OSTaskRemoteController.HANDLE_NOTIFICATION_OPEN + " operation from pending queue."); - handleNotificationOpen(context, data, fromAlert, notificationId); + handleNotificationOpen(context, data, fromHMSMessage, notificationId); } } }); @@ -2364,11 +2364,43 @@ public void run() { if (shouldInitDirectSessionFromNotificationOpen(context, data)) { applicationOpenedByNotification(notificationId); + + // HMS notification with Message Type being Message won't trigger Activity reverse trampolining logic + // for this case OneSignal rely on NotificationOpenedActivityHMS activity + // Last EMUI (12 to the date) is based on Android 10, so no + // Activity trampolining restriction exist for HMS devices + if (OSUtils.isHuaweiDeviceType() && fromHMSMessage) { + // Start activity with an activity trampolining + startOrResumeApp(context); + } } runNotificationOpenedCallback(data); } + // This opens the app in the same way an Android home screen launcher does. + // This means we expect the following behavior: + // 1. Starts the Activity defined in the app's AndroidManifest.xml as "android.intent.action.MAIN" + // 2. If the app is already running, instead the last activity will be resumed + // 3. If the app is not running (due to being push out of memory), the last activity will be resumed + // 4. If the app is no longer in the recent apps list, it is not resumed, same as #1 above. + // - App is removed from the recent app's list if it is swiped away or "clear all" is pressed. + static boolean startOrResumeApp(@NonNull Activity activity) { + Intent launchIntent = activity.getPackageManager().getLaunchIntentForPackage(activity.getPackageName()); + logger.debug("startOrResumeApp from context: " + activity + " isRoot: " + activity.isTaskRoot() + " with launchIntent: " + launchIntent); + + // Not all apps have a launcher intent, such as one that only provides a homescreen widget + if (launchIntent == null) + return false; + // Removing package from the intent, this treats the app as if it was started externally. + // This gives us the resume app behavior noted above. + // Android 11 no longer requires nulling this out to get this behavior. + launchIntent.setPackage(null); + + activity.startActivity(launchIntent); + return true; + } + private static boolean shouldInitDirectSessionFromNotificationOpen(Activity context, final JSONArray data) { if (inForeground) { return false; diff --git a/OneSignalSDK/unittest/src/test/java/com/onesignal/OneSignalPackagePrivateHelper.java b/OneSignalSDK/unittest/src/test/java/com/onesignal/OneSignalPackagePrivateHelper.java index 938111110a..ff73b9b7de 100644 --- a/OneSignalSDK/unittest/src/test/java/com/onesignal/OneSignalPackagePrivateHelper.java +++ b/OneSignalSDK/unittest/src/test/java/com/onesignal/OneSignalPackagePrivateHelper.java @@ -129,8 +129,8 @@ public static JSONObject bundleAsJSONObject(Bundle bundle) { return NotificationBundleProcessor.bundleAsJSONObject(bundle); } - public static void OneSignal_handleNotificationOpen(Activity context, final JSONArray data, final boolean fromAlert, final String notificationId) { - OneSignal.handleNotificationOpen(context, data, fromAlert, notificationId); + public static void OneSignal_handleNotificationOpen(Activity context, final JSONArray data, final boolean fromHMSMessage, final String notificationId) { + OneSignal.handleNotificationOpen(context, data, fromHMSMessage, notificationId); } public static BigInteger OneSignal_getAccentColor(JSONObject fcmJson) { From 0c7aecf16a14f2014210f9ec3ed8e120695c4f85 Mon Sep 17 00:00:00 2001 From: Jeasmine Nahui Date: Tue, 15 Feb 2022 13:30:21 -0300 Subject: [PATCH 2/2] Abstract HMS logic from handleNotificationOpen --- .../onesignal/NotificationPayloadProcessorHMS.java | 4 ++++ .../src/main/java/com/onesignal/OneSignal.java | 12 +++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/NotificationPayloadProcessorHMS.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/NotificationPayloadProcessorHMS.java index d47289c557..b437553c44 100644 --- a/OneSignalSDK/onesignal/src/main/java/com/onesignal/NotificationPayloadProcessorHMS.java +++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/NotificationPayloadProcessorHMS.java @@ -73,6 +73,10 @@ private static void handleProcessJsonOpenData(@NonNull Activity activity, @NonNu ); } + // HMS notification with Message Type being Message won't trigger Activity reverse trampolining logic + // for this case OneSignal rely on NotificationOpenedActivityHMS activity + // Last EMUI (12 to the date) is based on Android 10, so no + // Activity trampolining restriction exist for HMS devices public static void processDataMessageReceived(@NonNull final Context context, @Nullable String data) { OneSignal.initWithContext(context); if (data == null) diff --git a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignal.java b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignal.java index 32176dbf17..92c4762154 100644 --- a/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignal.java +++ b/OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignal.java @@ -2336,7 +2336,7 @@ static void fireForegroundHandlers(OSNotificationController notificationControll /** * Method called when opening a notification */ - static void handleNotificationOpen(final Activity context, final JSONArray data, final boolean fromHMSMessage, @Nullable final String notificationId) { + static void handleNotificationOpen(final Activity context, final JSONArray data, final boolean startLauncherActivity, @Nullable final String notificationId) { // Delay call until remote params are set if (taskRemoteController.shouldQueueTaskForInit(OSTaskRemoteController.HANDLE_NOTIFICATION_OPEN)) { logger.error("Waiting for remote params. " + @@ -2346,7 +2346,7 @@ static void handleNotificationOpen(final Activity context, final JSONArray data, public void run() { if (appContext != null) { logger.debug("Running " + OSTaskRemoteController.HANDLE_NOTIFICATION_OPEN + " operation from pending queue."); - handleNotificationOpen(context, data, fromHMSMessage, notificationId); + handleNotificationOpen(context, data, startLauncherActivity, notificationId); } } }); @@ -2365,11 +2365,7 @@ public void run() { if (shouldInitDirectSessionFromNotificationOpen(context, data)) { applicationOpenedByNotification(notificationId); - // HMS notification with Message Type being Message won't trigger Activity reverse trampolining logic - // for this case OneSignal rely on NotificationOpenedActivityHMS activity - // Last EMUI (12 to the date) is based on Android 10, so no - // Activity trampolining restriction exist for HMS devices - if (OSUtils.isHuaweiDeviceType() && fromHMSMessage) { + if (startLauncherActivity) { // Start activity with an activity trampolining startOrResumeApp(context); } @@ -2378,6 +2374,8 @@ public void run() { runNotificationOpenedCallback(data); } + // Reverse activity trampolining is used for most notifications. + // This method is only used if the push provider does support it. // This opens the app in the same way an Android home screen launcher does. // This means we expect the following behavior: // 1. Starts the Activity defined in the app's AndroidManifest.xml as "android.intent.action.MAIN"