4141import android .util .Log ;
4242import androidx .annotation .NonNull ;
4343import androidx .annotation .Nullable ;
44+ import androidx .annotation .VisibleForTesting ;
4445import androidx .core .app .NotificationCompat ;
4546import androidx .core .content .ContextCompat ;
46- import com .google .firebase . messaging . Constants .IntentActionKeys ;
47- import com .google .firebase . messaging . Constants .IntentKeys ;
47+ import com .google .android . gms . cloudmessaging . CloudMessagingReceiver .IntentActionKeys ;
48+ import com .google .android . gms . cloudmessaging . CloudMessagingReceiver .IntentKeys ;
4849import com .google .firebase .messaging .Constants .MessageNotificationKeys ;
4950import java .util .concurrent .atomic .AtomicInteger ;
5051
@@ -66,6 +67,16 @@ public final class CommonNotificationBuilder {
6667 public static final String FCM_FALLBACK_NOTIFICATION_CHANNEL_LABEL =
6768 "fcm_fallback_notification_channel_label" ;
6869
70+ // FM's fallback channel name when neither channel name is explicitly provided nor FM's string
71+ // resource file exists (possibly stripped by Progurad). Note this name is set purposefully
72+ // different from FM's default resource channel name "Miscellaneous" for debugability.
73+ private static final String FCM_FALLBACK_NOTIFICATION_CHANNEL_NAME_NO_RESOURCE = "Misc" ;
74+ private static final String ACTION_MESSAGING_EVENT = "com.google.firebase.MESSAGING_EVENT" ;
75+
76+ // Getting illegal resouce id from context will throw NotFoundException.
77+ // See: https://developer.android.com/reference/android/content/res/Resources#ID_NULL
78+ private static final int ILLEGAL_RESOURCE_ID = 0 ;
79+
6980 /**
7081 * Request code used by display notification pending intents.
7182 *
@@ -369,16 +380,16 @@ private static PendingIntent createContentIntent(
369380 // and google.n.).
370381 intent .putExtras (params .paramsWithReservedKeysRemoved ());
371382
372- PendingIntent contentIntent =
373- PendingIntent .getActivity (
374- context , generatePendingIntentRequestCode (), intent , PendingIntent .FLAG_ONE_SHOT );
375-
376- // We need to check metric options against the messageData bundle because we stripped the metric
377- // options from the clientVisibleData version
378383 if (shouldUploadMetrics (params )) {
379- contentIntent = wrapContentIntent (context , params , contentIntent );
384+ // store the analytics data in a sub-bundle
385+ intent .putExtra (MessageNotificationKeys .ANALYTICS_DATA , params .paramsForAnalyticsIntent ());
380386 }
381- return contentIntent ;
387+
388+ return PendingIntent .getActivity (
389+ context ,
390+ generatePendingIntentRequestCode (),
391+ intent ,
392+ getPendingIntentFlags (PendingIntent .FLAG_ONE_SHOT ));
382393 }
383394
384395 private static Intent createTargetIntent (
@@ -422,7 +433,8 @@ private static Bundle getManifestMetadata(PackageManager pm, String packageName)
422433 }
423434
424435 @ TargetApi (VERSION_CODES .O )
425- private static String getOrCreateChannel (
436+ @ VisibleForTesting
437+ public static String getOrCreateChannel (
426438 Context context , String msgChannel , Bundle manifestMetadata ) {
427439 if (Build .VERSION .SDK_INT < VERSION_CODES .O ) {
428440 return null ;
@@ -483,12 +495,24 @@ private static String getOrCreateChannel(
483495 .getIdentifier (
484496 FCM_FALLBACK_NOTIFICATION_CHANNEL_LABEL , "string" , context .getPackageName ());
485497
498+ String defaultChannelName ;
499+ if (channelLabelResourceId == ILLEGAL_RESOURCE_ID ) {
500+ Log .e (
501+ TAG ,
502+ "String resource \" fcm_fallback_notification_channel_label\" is not found. Using"
503+ + " default string channel name." );
504+
505+ defaultChannelName = FCM_FALLBACK_NOTIFICATION_CHANNEL_NAME_NO_RESOURCE ;
506+ } else {
507+ defaultChannelName = context .getString (channelLabelResourceId );
508+ }
509+
486510 notificationManager .createNotificationChannel (
487511 new NotificationChannel (
488512 // channel id
489513 FCM_FALLBACK_NOTIFICATION_CHANNEL ,
490514 // user visible name of the channel
491- context . getString ( channelLabelResourceId ) ,
515+ defaultChannelName ,
492516 // shows everywhere, makes noise, but does not visually intrude.
493517 NotificationManager .IMPORTANCE_DEFAULT ));
494518 }
@@ -505,16 +529,15 @@ private static int generatePendingIntentRequestCode() {
505529 return requestCodeProvider .incrementAndGet ();
506530 }
507531
508- private static PendingIntent wrapContentIntent (
509- Context context , NotificationParams params , PendingIntent pi ) {
510- // Need to send analytics, so wrap the activity intent in a PendingIntent that starts the
511- // FirebaseMessagingService. The service will launch the activity and send the analytics.
512- Intent openIntent =
513- new Intent (IntentActionKeys .NOTIFICATION_OPEN )
514- .putExtras (params .paramsForAnalyticsIntent ())
515- .putExtra (IntentKeys .PENDING_INTENT , pi );
516-
517- return createMessagingPendingIntent (context , openIntent );
532+ /**
533+ * Adds {@link PendingIntent#FLAG_IMMUTABLE} to a PendingIntent's flags since any PendingIntents
534+ * used here don't need to be modified.
535+ */
536+ private static int getPendingIntentFlags (int baseFlags ) {
537+ // Only add on platform levels that support FLAG_IMMUTABLE.
538+ return Build .VERSION .SDK_INT >= Build .VERSION_CODES .M
539+ ? baseFlags | PendingIntent .FLAG_IMMUTABLE
540+ : baseFlags ;
518541 }
519542
520543 @ Nullable
@@ -535,11 +558,11 @@ private static PendingIntent createMessagingPendingIntent(Context context, Inten
535558 return PendingIntent .getBroadcast (
536559 context ,
537560 generatePendingIntentRequestCode (),
538- new Intent (IntentActionKeys . MESSAGING_EVENT )
561+ new Intent (ACTION_MESSAGING_EVENT )
539562 .setComponent (
540563 new ComponentName (context , "com.google.firebase.iid.FirebaseInstanceIdReceiver" ))
541564 .putExtra (IntentKeys .WRAPPED_INTENT , intent ),
542- PendingIntent .FLAG_ONE_SHOT );
565+ getPendingIntentFlags ( PendingIntent .FLAG_ONE_SHOT ) );
543566 }
544567
545568 /** Check whether we should upload metrics data. */
0 commit comments