Skip to content

Commit c208afe

Browse files
authored
Merge pull request #1581 from OneSignal/change/notification_activity_trampoline_forward_instead_of_reverse
[Change] Notification Activity Trampoline forward instead of reverse
2 parents 0443c85 + 1c3e69e commit c208afe

13 files changed

+304
-241
lines changed

OneSignalSDK/onesignal/src/main/java/com/onesignal/GenerateNotification.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -275,9 +275,8 @@ private static boolean showNotification(OSNotificationGenerationJob notification
275275
JSONObject fcmJson = notificationJob.getJsonPayload();
276276
String group = fcmJson.optString("grp", null);
277277

278-
GenerateNotificationOpenIntent intentGenerator = GenerateNotificationOpenIntentFromPushPayload.INSTANCE.create(
279-
currentContext,
280-
fcmJson
278+
IntentGeneratorForAttachingToNotifications intentGenerator = new IntentGeneratorForAttachingToNotifications(
279+
currentContext
281280
);
282281

283282
ArrayList<StatusBarNotification> grouplessNotifs = new ArrayList<>();
@@ -368,7 +367,7 @@ private static boolean showNotification(OSNotificationGenerationJob notification
368367

369368
private static Notification createGenericPendingIntentsForNotif(
370369
NotificationCompat.Builder notifBuilder,
371-
GenerateNotificationOpenIntent intentGenerator,
370+
IntentGeneratorForAttachingToNotifications intentGenerator,
372371
JSONObject gcmBundle,
373372
int notificationId
374373
) {
@@ -385,7 +384,7 @@ private static Notification createGenericPendingIntentsForNotif(
385384

386385
private static void createGenericPendingIntentsForGroup(
387386
NotificationCompat.Builder notifBuilder,
388-
GenerateNotificationOpenIntent intentGenerator,
387+
IntentGeneratorForAttachingToNotifications intentGenerator,
389388
JSONObject gcmBundle,
390389
String group,
391390
int notificationId
@@ -495,9 +494,8 @@ static void updateSummaryNotification(OSNotificationGenerationJob notificationJo
495494
private static void createSummaryNotification(OSNotificationGenerationJob notificationJob, OneSignalNotificationBuilder notifBuilder) {
496495
boolean updateSummary = notificationJob.isRestoring();
497496
JSONObject fcmJson = notificationJob.getJsonPayload();
498-
GenerateNotificationOpenIntent intentGenerator = GenerateNotificationOpenIntentFromPushPayload.INSTANCE.create(
499-
currentContext,
500-
fcmJson
497+
IntentGeneratorForAttachingToNotifications intentGenerator = new IntentGeneratorForAttachingToNotifications(
498+
currentContext
501499
);
502500

503501
String group = fcmJson.optString("grp", null);
@@ -706,7 +704,7 @@ private static void createSummaryNotification(OSNotificationGenerationJob notifi
706704
@RequiresApi(api = Build.VERSION_CODES.M)
707705
private static void createGrouplessSummaryNotification(
708706
OSNotificationGenerationJob notificationJob,
709-
GenerateNotificationOpenIntent intentGenerator,
707+
IntentGeneratorForAttachingToNotifications intentGenerator,
710708
int grouplessNotifCount
711709
) {
712710
JSONObject fcmJson = notificationJob.getJsonPayload();
@@ -763,7 +761,7 @@ private static void createGrouplessSummaryNotification(
763761

764762
private static Intent createBaseSummaryIntent(
765763
int summaryNotificationId,
766-
GenerateNotificationOpenIntent intentGenerator,
764+
IntentGeneratorForAttachingToNotifications intentGenerator,
767765
JSONObject fcmJson,
768766
String group
769767
) {
@@ -1034,7 +1032,7 @@ static BigInteger getAccentColor(JSONObject fcmJson) {
10341032

10351033
private static void addNotificationActionButtons(
10361034
JSONObject fcmJson,
1037-
GenerateNotificationOpenIntent intentGenerator,
1035+
IntentGeneratorForAttachingToNotifications intentGenerator,
10381036
NotificationCompat.Builder mBuilder,
10391037
int notificationId,
10401038
String groupSummary

OneSignalSDK/onesignal/src/main/java/com/onesignal/GenerateNotificationOpenIntent.kt

Lines changed: 6 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,128 +1,31 @@
11
package com.onesignal
22

3-
import android.app.PendingIntent
43
import android.content.Context
54
import android.content.Intent
6-
import androidx.annotation.RequiresApi
75

86
class GenerateNotificationOpenIntent(
97
private val context: Context,
108
private val intent: Intent?,
119
private val startApp: Boolean
1210
) {
13-
14-
private val notificationOpenedClassAndroid23Plus: Class<*> = NotificationOpenedReceiver::class.java
15-
private val notificationOpenedClassAndroid22AndOlder: Class<*> = NotificationOpenedReceiverAndroid22AndOlder::class.java
16-
17-
fun getNewBaseIntent(
18-
notificationId: Int,
19-
): Intent {
20-
val intent =
21-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M)
22-
getNewBaseIntentAndroidAPI23Plus()
23-
else
24-
getNewBaseIntentAndroidAPI22AndOlder()
25-
26-
return intent
27-
.putExtra(
28-
GenerateNotification.BUNDLE_KEY_ANDROID_NOTIFICATION_ID,
29-
notificationId
30-
)
31-
// We use SINGLE_TOP and CLEAR_TOP as we don't want more than one OneSignal invisible click
32-
// tracking Activity instance around.
33-
.addFlags(
34-
Intent.FLAG_ACTIVITY_SINGLE_TOP or
35-
Intent.FLAG_ACTIVITY_CLEAR_TOP
36-
)
37-
}
38-
39-
@RequiresApi(android.os.Build.VERSION_CODES.M)
40-
private fun getNewBaseIntentAndroidAPI23Plus(): Intent {
41-
return Intent(
42-
context,
43-
notificationOpenedClassAndroid23Plus
44-
)
45-
}
46-
47-
// See NotificationOpenedReceiverAndroid22AndOlder.kt for details
48-
@Deprecated("Use getNewBaseIntentAndroidAPI23Plus instead for Android 6+")
49-
private fun getNewBaseIntentAndroidAPI22AndOlder(): Intent {
50-
val intent = Intent(
51-
context,
52-
notificationOpenedClassAndroid22AndOlder
53-
)
54-
55-
if (getIntentVisible() == null) {
56-
// If we don't show a visible Activity put OneSignal's invisible click tracking
57-
// Activity on it's own task so it doesn't resume an existing one once it closes.
58-
intent.addFlags(
59-
Intent.FLAG_ACTIVITY_NEW_TASK or
60-
Intent.FLAG_ACTIVITY_MULTIPLE_TASK or
61-
Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
62-
)
63-
}
64-
65-
return intent
11+
fun getIntentVisible(): Intent? {
12+
if (intent != null) return intent
13+
return getIntentAppOpen()
6614
}
6715

6816
/**
69-
* Creates a PendingIntent to attach to the notification click and it's action button(s).
70-
* If the user interacts with the notification this normally starts the app or resumes it
71-
* unless the app developer disables this via a OneSignal meta-data AndroidManifest.xml setting
72-
*
73-
* The default behavior is to open the app in the same way an Android homescreen launcher does.
17+
* This opens the app in the same way an Android homescreen launcher does.
7418
* This means we expect the following behavior:
7519
* 1. Starts the Activity defined in the app's AndroidManifest.xml as "android.intent.action.MAIN"
7620
* 2. If the app is already running, instead the last activity will be resumed
7721
* 3. If the app is not running (due to being push out of memory), the last activity will be resumed
7822
* 4. If the app is no longer in the recent apps list, it is not resumed, same as #1 above.
79-
* - App is removed from the recent app's list if it is swiped away or "clear all" is pressed.
23+
* - App is removed from the recent app's list if it is swiped away or "clear all" is pressed.
8024
*/
81-
fun getNewActionPendingIntent(
82-
requestCode: Int,
83-
oneSignalIntent: Intent,
84-
): PendingIntent? {
85-
val flags = PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
86-
val launchIntent = getIntentVisible()
87-
?:
88-
// Even though the default app open action is disabled we still need to attach OneSignal's
89-
// invisible Activity to capture click event to report click counts and etc.
90-
// You may be thinking why not use a BroadcastReceiver instead of an invisible
91-
// Activity? This could be done in a 5.0.0 release but can't be changed now as it is
92-
// unknown if the app developer will be starting there own Activity from their
93-
// OSNotificationOpenedHandler and that would have side-effects.
94-
return PendingIntent.getActivity(
95-
context,
96-
requestCode,
97-
oneSignalIntent,
98-
flags
99-
)
100-
101-
102-
// This setups up a "Reverse Activity Trampoline"
103-
// The first Activity to launch will be oneSignalIntent, which is an invisible
104-
// Activity to track the click, fire OSNotificationOpenedHandler, etc. This Activity
105-
// will finish quickly and the destination Activity, launchIntent, will be shown to the user
106-
// since it is the next in the back stack.
107-
return PendingIntent.getActivities(
108-
context,
109-
requestCode,
110-
arrayOf(launchIntent, oneSignalIntent),
111-
flags
112-
)
113-
}
114-
115-
// Return the provide intent if one was set, otherwise default to opening the app.
116-
private fun getIntentVisible(): Intent? {
117-
if (intent != null) return intent
118-
return getIntentAppOpen()
119-
}
120-
121-
// Provides the default launcher Activity, if the app has one.
122-
// - This is almost always true, one of the few exceptions being an app that is only a widget.
12325
private fun getIntentAppOpen(): Intent? {
12426
if (!startApp) return null
12527

28+
// Is null for apps that only provide a widget for it's UI.
12629
val launchIntent =
12730
context.packageManager.getLaunchIntentForPackage(
12831
context.packageName
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.onesignal
2+
3+
import android.app.PendingIntent
4+
import android.content.Context
5+
import android.content.Intent
6+
import androidx.annotation.RequiresApi
7+
8+
class IntentGeneratorForAttachingToNotifications(
9+
val context: Context
10+
) {
11+
private val notificationOpenedClassAndroid23Plus: Class<*> = NotificationOpenedReceiver::class.java
12+
private val notificationOpenedClassAndroid22AndOlder: Class<*> = NotificationOpenedReceiverAndroid22AndOlder::class.java
13+
14+
fun getNewBaseIntent(
15+
notificationId: Int,
16+
): Intent {
17+
val intent =
18+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M)
19+
getNewBaseIntentAndroidAPI23Plus()
20+
else
21+
getNewBaseIntentAndroidAPI22AndOlder()
22+
23+
return intent
24+
.putExtra(
25+
GenerateNotification.BUNDLE_KEY_ANDROID_NOTIFICATION_ID,
26+
notificationId
27+
)
28+
// We use SINGLE_TOP and CLEAR_TOP as we don't want more than one OneSignal invisible click
29+
// tracking Activity instance around.
30+
.addFlags(
31+
Intent.FLAG_ACTIVITY_SINGLE_TOP or
32+
Intent.FLAG_ACTIVITY_CLEAR_TOP
33+
)
34+
}
35+
36+
@RequiresApi(android.os.Build.VERSION_CODES.M)
37+
private fun getNewBaseIntentAndroidAPI23Plus(): Intent {
38+
return Intent(
39+
context,
40+
notificationOpenedClassAndroid23Plus
41+
)
42+
}
43+
44+
// See NotificationOpenedReceiverAndroid22AndOlder.kt for details
45+
@Deprecated("Use getNewBaseIntentAndroidAPI23Plus instead for Android 6+")
46+
private fun getNewBaseIntentAndroidAPI22AndOlder(): Intent {
47+
val intent = Intent(
48+
context,
49+
notificationOpenedClassAndroid22AndOlder
50+
)
51+
intent.addFlags(
52+
Intent.FLAG_ACTIVITY_NEW_TASK or
53+
Intent.FLAG_ACTIVITY_MULTIPLE_TASK or
54+
Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
55+
)
56+
return intent
57+
}
58+
59+
fun getNewActionPendingIntent(
60+
requestCode: Int,
61+
oneSignalIntent: Intent,
62+
): PendingIntent? {
63+
val flags = PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
64+
return PendingIntent.getActivity(
65+
context,
66+
requestCode,
67+
oneSignalIntent,
68+
flags
69+
)
70+
}
71+
}

OneSignalSDK/onesignal/src/main/java/com/onesignal/NotificationBundleProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ static void processBundleFromReceiver(Context context, final Bundle bundle, fina
372372
bundleResult.setOneSignalPayload(true);
373373
maximizeButtonsFromBundle(bundle);
374374

375-
if (OSInAppMessagePreviewHandler.inAppMessagePreviewHandled(context, bundle)) {
375+
if (OSInAppMessagePreviewHandler.notificationReceived(context, bundle)) {
376376
// Return early, we don't want the extender service or etc. to fire for IAM previews
377377
bundleResult.setInAppPreviewShown(true);
378378
bundleReceiverCallback.onBundleProcessed(bundleResult);

OneSignalSDK/onesignal/src/main/java/com/onesignal/NotificationOpenedProcessor.java

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ static void processIntent(Context context, Intent intent) {
114114
if (!(context instanceof Activity))
115115
OneSignal.onesignalLog(OneSignal.LOG_LEVEL.ERROR, "NotificationOpenedProcessor processIntent from an non Activity context: " + context);
116116
else OneSignal.handleNotificationOpen((Activity) context, intentExtras.getDataArray(),
117-
false, OSNotificationFormatHelper.getOSNotificationIdFromJson(intentExtras.getJsonData()));
117+
OSNotificationFormatHelper.getOSNotificationIdFromJson(intentExtras.getJsonData()));
118118
}
119119
}
120120

@@ -126,7 +126,7 @@ static OSNotificationIntentExtras processToOpenIntent(Context context, Intent in
126126

127127
if (!(context instanceof Activity))
128128
OneSignal.onesignalLog(OneSignal.LOG_LEVEL.ERROR, "NotificationOpenedProcessor processIntent from an non Activity context: " + context);
129-
else if (handleIAMPreviewOpen((Activity) context, jsonData))
129+
else if (OSInAppMessagePreviewHandler.notificationOpened((Activity) context, jsonData))
130130
return null;
131131

132132
jsonData.put(BUNDLE_KEY_ANDROID_NOTIFICATION_ID, intent.getIntExtra(BUNDLE_KEY_ANDROID_NOTIFICATION_ID, 0));
@@ -143,15 +143,6 @@ else if (handleIAMPreviewOpen((Activity) context, jsonData))
143143
return new OSNotificationIntentExtras(dataArray, jsonData);
144144
}
145145

146-
static boolean handleIAMPreviewOpen(@NonNull Activity context, @NonNull JSONObject jsonData) {
147-
String previewUUID = OSInAppMessagePreviewHandler.inAppPreviewPushUUID(jsonData);
148-
if (previewUUID == null)
149-
return false;
150-
151-
OneSignal.getInAppMessageController().displayPreviewMessage(previewUUID);
152-
return true;
153-
}
154-
155146
private static void addChildNotifications(JSONArray dataArray, String summaryGroup, OneSignalDbHelper writableDb) {
156147
String[] retColumn = { NotificationTable.COLUMN_NAME_FULL_DATA };
157148
String[] whereArgs = { summaryGroup };

OneSignalSDK/onesignal/src/main/java/com/onesignal/NotificationPayloadProcessorHMS.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,12 @@ private static void reformatButtonClickAction(@NonNull JSONObject jsonData) {
6262
}
6363

6464
private static void handleProcessJsonOpenData(@NonNull Activity activity, @NonNull JSONObject jsonData) {
65-
if (NotificationOpenedProcessor.handleIAMPreviewOpen(activity, jsonData))
65+
if (OSInAppMessagePreviewHandler.notificationOpened(activity, jsonData))
6666
return;
6767

6868
OneSignal.handleNotificationOpen(
6969
activity,
7070
new JSONArray().put(jsonData),
71-
true,
7271
OSNotificationFormatHelper.getOSNotificationIdFromJson(jsonData)
7372
);
7473
}

OneSignalSDK/onesignal/src/main/java/com/onesignal/OSInAppMessagePreviewHandler.kt

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
package com.onesignal
22

3+
import android.app.Activity
34
import android.content.Context
45
import android.os.Build
56
import android.os.Bundle
7+
import androidx.annotation.ChecksSdkIntAtLeast
8+
import org.json.JSONArray
69
import org.json.JSONException
710
import org.json.JSONObject
811

912
internal object OSInAppMessagePreviewHandler {
1013
@JvmStatic
11-
fun inAppMessagePreviewHandled(context: Context?, bundle: Bundle?): Boolean {
14+
fun notificationReceived(context: Context?, bundle: Bundle?): Boolean {
1215
val pushPayloadJson = NotificationBundleProcessor.bundleAsJSONObject(bundle)
1316
// Show In-App message preview it is in the payload & the app is in focus
1417
val previewUUID = inAppPreviewPushUUID(pushPayloadJson) ?: return false
@@ -23,6 +26,15 @@ internal object OSInAppMessagePreviewHandler {
2326
return true
2427
}
2528

29+
@JvmStatic
30+
fun notificationOpened(activity: Activity, jsonData: JSONObject): Boolean {
31+
val previewUUID = inAppPreviewPushUUID(jsonData) ?: return false
32+
33+
OneSignal.openDestinationActivity(activity, JSONArray().put(jsonData))
34+
OneSignal.getInAppMessageController().displayPreviewMessage(previewUUID)
35+
return true
36+
}
37+
2638
@JvmStatic
2739
fun inAppPreviewPushUUID(payload: JSONObject): String? {
2840
val osCustom: JSONObject = try {
@@ -43,5 +55,6 @@ internal object OSInAppMessagePreviewHandler {
4355
}
4456

4557
// Validate that the current Android device is Android 4.4 or higher
58+
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.KITKAT)
4659
private fun shouldDisplayNotification(): Boolean = Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2
47-
}
60+
}

0 commit comments

Comments
 (0)