Skip to content

Commit a544544

Browse files
Fix(pinpoint) 2762: Resolve Android 12 notification trampolining restrictions and ADM Push Notifications (#2925)
* Resolve Android 12 notification trampolining restrictions * Update pinpoint notification test * set correct target class for ADM * remove line from test Co-authored-by: Divyesh Chitroda <[email protected]>
1 parent f34d1e7 commit a544544

File tree

10 files changed

+114
-53
lines changed

10 files changed

+114
-53
lines changed

aws-android-sdk-pinpoint/src/main/AndroidManifest.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,12 @@
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
33
package="com.amazonaws.services.pinpoint">
44
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
5+
<application>
6+
<activity
7+
android:name="com.amazonaws.mobileconnectors.pinpoint.targeting.notification.PinpointNotificationActivity"
8+
android:theme="@style/PinpointNotificationActivityTheme"
9+
android:launchMode="singleInstance"
10+
android:exported="false" />
11+
</application>
512
</manifest>
613

aws-android-sdk-pinpoint/src/main/java/com/amazonaws/mobileconnectors/pinpoint/PinpointManager.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
import com.amazonaws.mobileconnectors.pinpoint.targeting.TargetingClient;
2929
import com.amazonaws.mobileconnectors.pinpoint.targeting.notification.DeviceTokenRegisteredHandler;
3030
import com.amazonaws.mobileconnectors.pinpoint.targeting.notification.NotificationClient;
31-
import com.amazonaws.mobileconnectors.pinpoint.targeting.notification.PinpointNotificationReceiver;
31+
import com.amazonaws.mobileconnectors.pinpoint.targeting.notification.PinpointNotificationActivity;
3232
import com.amazonaws.regions.Regions;
3333
import com.amazonaws.services.pinpoint.AmazonPinpointClient;
3434
import com.amazonaws.services.pinpoint.model.ChannelType;
@@ -87,7 +87,7 @@ public PinpointManager(final PinpointConfiguration config) {
8787
this.pinpointContext = new PinpointContext(analyticsServiceClient, targetingServiceClient, appContext, appId, SDK_INFO, config);
8888
this.notificationClient = NotificationClient.createClient(this.pinpointContext, channelType);
8989
this.pinpointContext.setNotificationClient(this.notificationClient);
90-
PinpointNotificationReceiver.setNotificationClient(this.notificationClient);
90+
PinpointNotificationActivity.setNotificationClient(this.notificationClient);
9191

9292
if (config.getEnableEvents()) {
9393
this.analyticsClient = new AnalyticsClient(this.pinpointContext);

aws-android-sdk-pinpoint/src/main/java/com/amazonaws/mobileconnectors/pinpoint/targeting/notification/ADMNotificationClient.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,10 @@ protected PendingIntent createOpenAppPendingIntent(final Bundle pushBundle, fina
5656
flags |= PendingIntent.FLAG_IMMUTABLE;
5757
}
5858

59-
contentIntent = PendingIntent.getService(pinpointContext.getApplicationContext(), requestId,
59+
contentIntent = PendingIntent.getActivity(pinpointContext.getApplicationContext(), requestId,
6060
this.notificationIntent(pushBundle, eventSourceId, requestId, NotificationClient.ADM_INTENT_ACTION,
6161
targetClass), flags);
62+
PinpointNotificationActivity.setNotificationClient(this);
6263
}
6364
return contentIntent;
6465

aws-android-sdk-pinpoint/src/main/java/com/amazonaws/mobileconnectors/pinpoint/targeting/notification/BaiduNotificationClient.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ protected PendingIntent createOpenAppPendingIntent(Bundle pushBundle, Class<?> t
4848
flags |= PendingIntent.FLAG_IMMUTABLE;
4949
}
5050

51-
contentIntent = PendingIntent.getBroadcast(pinpointContext.getApplicationContext(), requestId,
51+
contentIntent = PendingIntent.getActivity(pinpointContext.getApplicationContext(), requestId,
5252
this.notificationIntent(pushBundle, eventSourceId, requestId, NotificationClient.BAIDU_INTENT_ACTION,
5353
targetClass), flags);
54-
PinpointNotificationReceiver.setNotificationClient(this);
54+
PinpointNotificationActivity.setNotificationClient(this);
5555
}
5656
return contentIntent;
5757
}

aws-android-sdk-pinpoint/src/main/java/com/amazonaws/mobileconnectors/pinpoint/targeting/notification/GCMNotificationClient.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,11 @@ protected PendingIntent createOpenAppPendingIntent(final Bundle pushBundle, fina
5858
this.notificationIntent(pushBundle, eventSourceId, requestId, NotificationClient.GCM_INTENT_ACTION,
5959
targetClass), flags);
6060
} else {
61-
contentIntent = PendingIntent.getBroadcast(pinpointContext.getApplicationContext(), requestId,
61+
contentIntent = PendingIntent.getActivity(pinpointContext.getApplicationContext(), requestId,
6262
this.notificationIntent(pushBundle, eventSourceId, requestId, NotificationClient.FCM_INTENT_ACTION,
6363
targetClass), flags);
64-
PinpointNotificationReceiver.setNotificationClient(this);
64+
PinpointNotificationActivity.setNotificationClient(this);
6565
}
6666
return contentIntent;
67-
6867
}
6968
}

aws-android-sdk-pinpoint/src/main/java/com/amazonaws/mobileconnectors/pinpoint/targeting/notification/NotificationDetails.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ public NotificationDetails build() {
244244
}
245245

246246
notificationDetails.setFrom(from);
247-
notificationDetails.setTargetClass(PinpointNotificationReceiver.class);
247+
notificationDetails.setTargetClass(PinpointNotificationActivity.class);
248248
notificationDetails.setIntentAction(intentAction);
249249
notificationDetails.setNotificationChannelId(notificationChannelId);
250250
}
@@ -257,7 +257,7 @@ public NotificationDetails build() {
257257
}
258258
notificationDetails.setBundle(data);
259259
}
260-
notificationDetails.setTargetClass(serviceClass);
260+
notificationDetails.setTargetClass(PinpointNotificationActivity.class);
261261
notificationDetails.setIntentAction(intentAction);
262262
}
263263

@@ -277,7 +277,7 @@ public NotificationDetails build() {
277277
notificationDetails.setFrom(localFrom);
278278
notificationDetails.setBundle(localBundle);
279279
}
280-
notificationDetails.setTargetClass(PinpointNotificationReceiver.class);
280+
notificationDetails.setTargetClass(PinpointNotificationActivity.class);
281281
notificationDetails.setIntentAction(intentAction);
282282
} catch (JSONException e) {
283283
log.error("Unable to parse JSON message: " + e, e);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package com.amazonaws.mobileconnectors.pinpoint.targeting.notification;
17+
18+
import android.app.Activity;
19+
import android.content.Intent;
20+
import android.content.pm.PackageManager;
21+
import android.os.Bundle;
22+
23+
/**
24+
* The Amazon Pinpoint push notification tracking/routing activity.
25+
* This class is an Activity instead of BroadcastReceiver due to Android 12 restrictions around
26+
* notification trampolining.
27+
*/
28+
public class PinpointNotificationActivity extends Activity {
29+
private static String TAG = PinpointNotificationActivity.class.getSimpleName();
30+
31+
private static volatile NotificationClient notificationClient = null;
32+
33+
public static void setNotificationClient(NotificationClient notificationClient) {
34+
PinpointNotificationActivity.notificationClient = notificationClient;
35+
}
36+
37+
public static void setNotificationClient(NotificationClientBase notificationClientBase) {
38+
PinpointNotificationActivity.notificationClient = new NotificationClient(notificationClientBase);
39+
}
40+
41+
@Override
42+
public void onCreate(Bundle savedInstanceState) {
43+
super.onCreate(savedInstanceState);
44+
45+
Intent intent = getIntent();
46+
Bundle extras = intent.getExtras();
47+
if (notificationClient != null) {
48+
EventSourceType eventSourceType = EventSourceType.getEventSourceType(extras);
49+
notificationClient.handleNotificationOpen(eventSourceType.getAttributeParser().parseAttributes(extras), extras);
50+
} else {
51+
final PackageManager pm = getPackageManager();
52+
final Intent launchIntent = pm.getLaunchIntentForPackage(intent.getPackage());
53+
launchIntent.putExtras(extras);
54+
startActivity(launchIntent);
55+
}
56+
57+
finish();
58+
}
59+
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2016-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License").
55
* You may not use this file except in compliance with the License.
@@ -15,41 +15,19 @@
1515

1616
package com.amazonaws.mobileconnectors.pinpoint.targeting.notification;
1717

18-
import java.util.HashMap;
19-
import java.util.Map;
2018
import android.content.BroadcastReceiver;
2119
import android.content.Context;
2220
import android.content.Intent;
23-
import android.content.pm.PackageManager;
24-
import android.util.Log;
2521

2622
/**
27-
* The Amazon Pinpoint push notification receiver.
23+
* @deprecated This class is no longer functional and will soon be removed. At one point,
24+
* we required adding this receiver to the app manifest. That code block should be removed.
2825
*/
26+
@Deprecated
2927
public class PinpointNotificationReceiver extends BroadcastReceiver {
30-
private static String TAG = PinpointNotificationReceiver.class.getSimpleName();
31-
32-
private static volatile NotificationClient notificationClient = null;
33-
34-
public static void setNotificationClient(NotificationClient notificationClient) {
35-
PinpointNotificationReceiver.notificationClient = notificationClient;
36-
}
37-
38-
public static void setNotificationClient(NotificationClientBase notificationClientBase) {
39-
PinpointNotificationReceiver.notificationClient = new NotificationClient(notificationClientBase);
40-
}
4128

4229
@Override
4330
public void onReceive(Context context, Intent intent) {
44-
if (notificationClient != null) {
45-
EventSourceType eventSourceType = EventSourceType.getEventSourceType(intent.getExtras());
46-
notificationClient.handleNotificationOpen(eventSourceType.getAttributeParser().parseAttributes(intent.getExtras()),
47-
intent.getExtras());
48-
} else {
49-
final PackageManager pm = context.getPackageManager();
50-
final Intent launchIntent = pm.getLaunchIntentForPackage(intent.getPackage());
51-
launchIntent.putExtras(intent.getExtras());
52-
context.startActivity(launchIntent);
53-
}
31+
// do nothing
5432
}
5533
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<resources>
3+
4+
<!--This theme ensures the Headless PinpointNotificationActivity is completely hidden-->
5+
<style name="PinpointNotificationActivityTheme" parent="android:Theme">
6+
<item name="android:windowIsTranslucent">true</item>
7+
<item name="android:windowBackground">@android:color/transparent</item>
8+
<item name="android:windowContentOverlay">@null</item>
9+
<item name="android:windowNoTitle">true</item>
10+
<item name="android:windowIsFloating">true</item>
11+
<item name="android:backgroundDimEnabled">false</item>
12+
</style>
13+
14+
</resources>
Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,46 @@
22

33
import static org.mockito.Mockito.times;
44
import static org.mockito.Mockito.verify;
5+
import static org.mockito.Mockito.verifyZeroInteractions;
56

6-
import android.content.Context;
7-
import android.content.Intent;
87
import android.os.Bundle;
98

9+
import org.junit.After;
1010
import org.junit.Before;
1111
import org.junit.Test;
1212
import org.junit.runner.RunWith;
1313
import org.mockito.Mockito;
14+
import org.robolectric.Robolectric;
1415
import org.robolectric.RobolectricTestRunner;
1516
import org.robolectric.annotation.Config;
17+
import org.robolectric.android.controller.ActivityController;
1618

1719
@RunWith(RobolectricTestRunner.class)
1820
@Config(manifest = Config.NONE, sdk=23)
19-
public class PinpointNotificationReceiverTests {
21+
public class PinpointNotificationActivityTests {
2022

2123
private NotificationClient notificationClient;
22-
23-
private PinpointNotificationReceiver receiver;
24-
25-
private Intent intent;
26-
27-
private Context context;
24+
private ActivityController<PinpointNotificationActivity> activityController;
2825

2926
@Before
3027
public void setup() {
3128
notificationClient = Mockito.mock(NotificationClient.class);
32-
intent = Mockito.mock(Intent.class);
33-
receiver = new PinpointNotificationReceiver();
34-
PinpointNotificationReceiver.setNotificationClient(notificationClient);
35-
context = Mockito.mock(Context.class);
29+
activityController = Robolectric.buildActivity(PinpointNotificationActivity.class);
30+
PinpointNotificationActivity.setNotificationClient(notificationClient);
31+
}
32+
33+
@After
34+
public void tearDown() {
35+
activityController.destroy();
36+
PinpointNotificationActivity.setNotificationClient((NotificationClient) null);
3637
}
3738

3839
@Test
3940
public void testReferenceToNotificationClient() {
40-
System.gc();
41-
receiver.onReceive(context, intent);
41+
verifyZeroInteractions(notificationClient);
42+
43+
activityController.create();
44+
4245
verify(notificationClient, times(1)).handleNotificationOpen(Mockito.anyMap(),
4346
Mockito.any(Bundle.class));
4447
}

0 commit comments

Comments
 (0)