Skip to content

Commit 681aa43

Browse files
authored
Merge pull request #16082 from wordpress-mobile/issue/16065-pending-intent-mutability
Android 12: Security and privacy - Pending intents mutability
2 parents 0fff96f + 4e6407b commit 681aa43

File tree

13 files changed

+181
-161
lines changed

13 files changed

+181
-161
lines changed

WordPress/src/main/AndroidManifest.xml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,10 +1027,12 @@
10271027
android:resource="@xml/provider_paths"/>
10281028
</provider>
10291029

1030-
<!-- Remove the default WorkManagerInitializer so we can use our own -->
1030+
<!-- Remove the default WorkManagerInitializer so we can use our own
1031+
Since WorkManager 2.6, App Startup is used internally within WorkManager.
1032+
To provide a custom initializer we need to remove the androidx.startup node.-->
10311033
<provider
1032-
android:name="androidx.work.impl.WorkManagerInitializer"
1033-
android:authorities="${applicationId}.workmanager-init"
1034+
android:name="androidx.startup.InitializationProvider"
1035+
android:authorities="${applicationId}.androidx-startup"
10341036
tools:node="remove" />
10351037

10361038
</application>

WordPress/src/main/java/org/wordpress/android/push/GCMMessageHandler.java

Lines changed: 35 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,7 @@ public class GCMMessageHandler {
100100
private final ArrayMap<Integer, Bundle> mActiveNotificationsMap;
101101
private final NotificationHelper mNotificationHelper;
102102

103-
@Inject
104-
GCMMessageHandler(SystemNotificationsTracker systemNotificationsTracker) {
103+
@Inject GCMMessageHandler(SystemNotificationsTracker systemNotificationsTracker) {
105104
mActiveNotificationsMap = new ArrayMap<>();
106105
mNotificationHelper = new NotificationHelper(this, systemNotificationsTracker);
107106
}
@@ -544,27 +543,23 @@ private void addCommentApproveActionForCommentNotification(Context context, Noti
544543
}
545544

546545
private PendingIntent getCommentActionPendingIntent(Context context, Intent intent) {
547-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
548-
return getCommentActionPendingIntentForService(context, intent);
549-
} else {
550-
return getCommentActionPendingIntentForActivity(context, intent);
551-
}
546+
return getCommentActionPendingIntentForService(context, intent);
552547
}
553548

554549
private PendingIntent getCommentActionPendingIntentForService(Context context, Intent intent) {
555-
return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
556-
}
557-
558-
private PendingIntent getCommentActionPendingIntentForActivity(Context context, Intent intent) {
559-
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
550+
int flags = PendingIntent.FLAG_CANCEL_CURRENT;
551+
if (Build.VERSION.SDK_INT >= 31) flags |= PendingIntent.FLAG_MUTABLE;
552+
553+
return PendingIntent.getService(
554+
context,
555+
0,
556+
intent,
557+
flags
558+
);
560559
}
561560

562561
private Intent getCommentActionReplyIntent(Context context, String noteId) {
563-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
564-
return getCommentActionIntentForService(context);
565-
} else {
566-
return getCommentActionIntentForActivity(context, noteId);
567-
}
562+
return getCommentActionIntentForService(context);
568563
}
569564

570565
private Intent getCommentActionIntent(Context context) {
@@ -575,18 +570,6 @@ private Intent getCommentActionIntentForService(Context context) {
575570
return new Intent(context, NotificationsProcessingService.class);
576571
}
577572

578-
private Intent getCommentActionIntentForActivity(Context context, String noteId) {
579-
Intent intent = new Intent(context, WPMainActivity.class);
580-
intent.putExtra(WPMainActivity.ARG_OPENED_FROM_PUSH, true);
581-
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK
582-
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
583-
intent.setAction("android.intent.action.MAIN");
584-
intent.addCategory("android.intent.category.LAUNCHER");
585-
intent.putExtra(NotificationsListFragment.NOTE_ID_EXTRA, noteId);
586-
intent.putExtra(NotificationsListFragment.NOTE_INSTANT_REPLY_EXTRA, true);
587-
return intent;
588-
}
589-
590573
private Bitmap getLargeIconBitmap(Context context, String iconUrl, boolean shouldCircularizeIcon) {
591574
Bitmap largeIconBitmap = null;
592575
if (iconUrl != null) {
@@ -797,9 +780,13 @@ private void showNotificationForBuilder(NotificationCompat.Builder builder, Cont
797780
builder.setCategory(NotificationCompat.CATEGORY_SOCIAL);
798781

799782
resultIntent.putExtra(ARG_NOTIFICATION_TYPE, notificationType);
800-
PendingIntent pendingIntent = PendingIntent.getActivity(context, pushId, resultIntent,
801-
PendingIntent.FLAG_CANCEL_CURRENT
802-
| PendingIntent.FLAG_UPDATE_CURRENT);
783+
PendingIntent pendingIntent = PendingIntent.getActivity(
784+
context,
785+
pushId,
786+
resultIntent,
787+
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_UPDATE_CURRENT
788+
| PendingIntent.FLAG_IMMUTABLE
789+
);
803790
builder.setContentIntent(pendingIntent);
804791
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
805792
notificationManager.notify(pushId, builder.build());
@@ -992,9 +979,12 @@ private void handlePushAuth(Context context, Bundle data) {
992979
.setOnlyAlertOnce(true)
993980
.setPriority(NotificationCompat.PRIORITY_MAX);
994981

995-
PendingIntent pendingIntent =
996-
PendingIntent.getActivity(context, AUTH_PUSH_REQUEST_CODE_OPEN_DIALOG, pushAuthIntent,
997-
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_UPDATE_CURRENT);
982+
PendingIntent pendingIntent = PendingIntent.getActivity(
983+
context,
984+
AUTH_PUSH_REQUEST_CODE_OPEN_DIALOG,
985+
pushAuthIntent,
986+
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
987+
);
998988
builder.setContentIntent(pendingIntent);
999989

1000990

@@ -1013,9 +1003,12 @@ private void handlePushAuth(Context context, Bundle data) {
10131003
authApproveIntent.setAction("android.intent.action.MAIN");
10141004
authApproveIntent.addCategory("android.intent.category.LAUNCHER");
10151005

1016-
PendingIntent authApprovePendingIntent =
1017-
PendingIntent.getActivity(context, AUTH_PUSH_REQUEST_CODE_APPROVE, authApproveIntent,
1018-
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_UPDATE_CURRENT);
1006+
PendingIntent authApprovePendingIntent = PendingIntent.getActivity(
1007+
context,
1008+
AUTH_PUSH_REQUEST_CODE_APPROVE,
1009+
authApproveIntent,
1010+
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
1011+
);
10191012

10201013
builder.addAction(R.drawable.ic_checkmark_white_24dp, context.getText(R.string.approve),
10211014
authApprovePendingIntent);
@@ -1024,10 +1017,12 @@ private void handlePushAuth(Context context, Bundle data) {
10241017
Intent authIgnoreIntent = new Intent(context, NotificationsProcessingService.class);
10251018
authIgnoreIntent.putExtra(NotificationsProcessingService.ARG_ACTION_TYPE,
10261019
NotificationsProcessingService.ARG_ACTION_AUTH_IGNORE);
1027-
PendingIntent authIgnorePendingIntent = PendingIntent.getService(context,
1020+
PendingIntent authIgnorePendingIntent = PendingIntent.getService(
1021+
context,
10281022
AUTH_PUSH_REQUEST_CODE_IGNORE,
10291023
authIgnoreIntent,
1030-
PendingIntent.FLAG_CANCEL_CURRENT);
1024+
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE
1025+
);
10311026
builder.addAction(R.drawable.ic_close_white_24dp, context.getText(R.string.ignore),
10321027
authIgnorePendingIntent);
10331028

WordPress/src/main/java/org/wordpress/android/push/NotificationsProcessingService.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ public static PendingIntent getPendingIntentForNotificationDismiss(Context conte
135135
intent.putExtra(ARG_NOTIFICATION_TYPE, notificationType);
136136
intent.addCategory(ARG_ACTION_NOTIFICATION_DISMISS);
137137

138-
return PendingIntent.getService(context, pushId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
138+
return PendingIntent
139+
.getService(context, pushId, intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
139140
}
140141

141142
public static void stopService(Context context) {

WordPress/src/main/java/org/wordpress/android/ui/notifications/receivers/NotificationsPendingDraftsReceiver.java

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -135,15 +135,15 @@ private String getPostTitle(Context context, String postTitle) {
135135
private void buildSinglePendingDraftNotification(Context context, String postTitle, String formattedMessage,
136136
int postId, boolean isPage) {
137137
buildSinglePendingDraftNotification(context, getResultIntentForOnePost(context, postId, isPage),
138-
String.format(formattedMessage, getPostTitle(context, postTitle)), postId, isPage);
138+
String.format(formattedMessage, getPostTitle(context, postTitle)), postId, isPage);
139139
}
140140

141141
private void buildSinglePendingDraftNotificationGeneric(Context context, String postTitle, int postId,
142142
boolean isPage) {
143143
buildSinglePendingDraftNotification(context, getResultIntentForOnePost(context, postId, isPage),
144-
String.format(context.getString(R.string.pending_draft_one_generic),
145-
getPostTitle(context, postTitle)),
146-
postId, isPage);
144+
String.format(context.getString(R.string.pending_draft_one_generic),
145+
getPostTitle(context, postTitle)),
146+
postId, isPage);
147147
}
148148

149149
private PendingIntent getResultIntentForOnePost(Context context, int postId, boolean isPage) {
@@ -156,10 +156,12 @@ private PendingIntent getResultIntentForOnePost(Context context, int postId, boo
156156
resultIntent.putExtra(POST_ID_EXTRA, postId);
157157
resultIntent.putExtra(IS_PAGE_EXTRA, isPage);
158158
resultIntent.putExtra(ARG_NOTIFICATION_TYPE, NotificationType.PENDING_DRAFTS);
159-
PendingIntent pendingIntent = PendingIntent
160-
.getActivity(context, BASE_REQUEST_CODE + PendingDraftsNotificationsUtils
161-
.makePendingDraftNotificationId(postId),
162-
resultIntent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_UPDATE_CURRENT);
159+
PendingIntent pendingIntent = PendingIntent.getActivity(
160+
context,
161+
BASE_REQUEST_CODE + PendingDraftsNotificationsUtils.makePendingDraftNotificationId(postId),
162+
resultIntent,
163+
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
164+
);
163165

164166
return pendingIntent;
165167
}
@@ -180,8 +182,7 @@ private void buildSinglePendingDraftNotification(Context context, PendingIntent
180182
addDismissActionForNotification(context, builder, postId, isPage);
181183

182184
NativeNotificationsUtils.showMessageToUserWithBuilder(builder, message, false,
183-
PendingDraftsNotificationsUtils
184-
.makePendingDraftNotificationId(postId), context);
185+
PendingDraftsNotificationsUtils.makePendingDraftNotificationId(postId), context);
185186
mSystemNotificationsTracker.trackShownNotification(NotificationType.PENDING_DRAFTS);
186187
}
187188

@@ -194,52 +195,52 @@ private void addOpenDraftActionForNotification(Context context, NotificationComp
194195
openDraftIntent.putExtra(IS_PAGE_EXTRA, isPage);
195196
openDraftIntent.putExtra(ARG_NOTIFICATION_TYPE, NotificationType.PENDING_DRAFTS);
196197

197-
PendingIntent pendingIntent = PendingIntent
198-
.getActivity(context,
199-
// need to add + 2 so the request code is different, otherwise they overlap
200-
BASE_REQUEST_CODE + 1 + PendingDraftsNotificationsUtils
201-
.makePendingDraftNotificationId(postId),
202-
openDraftIntent,
203-
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_UPDATE_CURRENT);
204-
builder.addAction(R.drawable.ic_pencil_white_24dp, context.getText(R.string.edit),
205-
pendingIntent);
198+
PendingIntent pendingIntent = PendingIntent.getActivity(
199+
context,
200+
// need to add + 1 so the request code is different, otherwise they overlap
201+
BASE_REQUEST_CODE + 1 + PendingDraftsNotificationsUtils.makePendingDraftNotificationId(postId),
202+
openDraftIntent,
203+
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
204+
);
205+
builder.addAction(R.drawable.ic_pencil_white_24dp, context.getText(R.string.edit), pendingIntent);
206206
}
207207

208208
private void addIgnoreActionForNotification(Context context, NotificationCompat.Builder builder, int postId,
209209
boolean isPage) {
210210
// Call processing service when user taps on IGNORE - we should remember this decision for this post
211211
Intent ignoreIntent = new Intent(context, NotificationsProcessingService.class);
212212
ignoreIntent.putExtra(NotificationsProcessingService.ARG_ACTION_TYPE,
213-
NotificationsProcessingService.ARG_ACTION_DRAFT_PENDING_IGNORE);
213+
NotificationsProcessingService.ARG_ACTION_DRAFT_PENDING_IGNORE);
214214
ignoreIntent.putExtra(POST_ID_EXTRA, postId);
215215
ignoreIntent.putExtra(IS_PAGE_EXTRA, isPage);
216216
ignoreIntent.putExtra(ARG_NOTIFICATION_TYPE, NotificationType.PENDING_DRAFTS);
217-
PendingIntent ignorePendingIntent = PendingIntent
218-
.getService(context,
219-
// need to add + 2 so the request code is different, otherwise they overlap
220-
BASE_REQUEST_CODE + 2
221-
+ PendingDraftsNotificationsUtils.makePendingDraftNotificationId(postId),
222-
ignoreIntent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_UPDATE_CURRENT);
223-
builder.addAction(R.drawable.ic_close_white_24dp, context.getText(R.string.ignore),
224-
ignorePendingIntent);
217+
PendingIntent ignorePendingIntent = PendingIntent.getService(
218+
context,
219+
// need to add + 2 so the request code is different, otherwise they overlap
220+
BASE_REQUEST_CODE + 2 + PendingDraftsNotificationsUtils.makePendingDraftNotificationId(postId),
221+
ignoreIntent,
222+
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
223+
);
224+
builder.addAction(R.drawable.ic_close_white_24dp, context.getText(R.string.ignore), ignorePendingIntent);
225225
}
226226

227227
private void addDismissActionForNotification(Context context, NotificationCompat.Builder builder, int postId,
228228
boolean isPage) {
229229
// Call processing service when notification is dismissed
230230
Intent notificationDeletedIntent = new Intent(context, NotificationsProcessingService.class);
231231
notificationDeletedIntent.putExtra(NotificationsProcessingService.ARG_ACTION_TYPE,
232-
NotificationsProcessingService.ARG_ACTION_DRAFT_PENDING_DISMISS);
232+
NotificationsProcessingService.ARG_ACTION_DRAFT_PENDING_DISMISS);
233233
notificationDeletedIntent.putExtra(POST_ID_EXTRA, postId);
234234
notificationDeletedIntent.putExtra(IS_PAGE_EXTRA, isPage);
235235
notificationDeletedIntent.putExtra(NotificationsProcessingService.ARG_NOTIFICATION_TYPE,
236236
NotificationType.PENDING_DRAFTS);
237-
PendingIntent dismissPendingIntent = PendingIntent
238-
.getService(context,
239-
// need to add + 3 so the request code is different, otherwise they overlap
240-
BASE_REQUEST_CODE + 3
241-
+ PendingDraftsNotificationsUtils.makePendingDraftNotificationId(postId),
242-
notificationDeletedIntent, PendingIntent.FLAG_CANCEL_CURRENT);
237+
PendingIntent dismissPendingIntent = PendingIntent.getService(
238+
context,
239+
// need to add + 3 so the request code is different, otherwise they overlap
240+
BASE_REQUEST_CODE + 3 + PendingDraftsNotificationsUtils.makePendingDraftNotificationId(postId),
241+
notificationDeletedIntent,
242+
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE
243+
);
243244
builder.setDeleteIntent(dismissPendingIntent);
244245
}
245246
}

0 commit comments

Comments
 (0)