Tracks Android notification dismiss event.
This CL adds an API in ChromeNotificationBuilder to track notification
dismiss in UMA.
Bug: 898269
Change-Id: I0d33150eb98dfcd96c6807ab490519a39fe79101
Reviewed-on: https://chromium-review.googlesource.com/c/1387811
Reviewed-by: David Trainor <dtrainor@chromium.org>
Reviewed-by: Jesse Doherty <jwd@chromium.org>
Commit-Queue: Xing Liu <xingliu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#624351}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/ChromeNotificationBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/ChromeNotificationBuilder.java
index 0074a6f..a75413c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/ChromeNotificationBuilder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/ChromeNotificationBuilder.java
@@ -51,8 +51,11 @@
ChromeNotificationBuilder addAction(Notification.Action action);
+ @Deprecated
ChromeNotificationBuilder setDeleteIntent(PendingIntent intent);
+ ChromeNotificationBuilder setDeleteIntent(PendingIntentProvider intent);
+
/**
* Sets the priority of single notification on Android versions prior to Oreo.
* (From Oreo onwards, priority is instead determined by channel importance.)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilder.java
index 0324d666..bc473d10 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilder.java
@@ -34,6 +34,10 @@
mBuilder.setChannelId(channelId);
}
mMetadata = metadata;
+ if (mMetadata != null) {
+ mBuilder.setDeleteIntent(
+ NotificationIntentInterceptor.getDefaultDeletePendingIntent(mMetadata));
+ }
}
@Override
@@ -173,6 +177,15 @@
}
@Override
+ public ChromeNotificationBuilder setDeleteIntent(PendingIntentProvider intent) {
+ assert (mMetadata != null);
+ mBuilder.setDeleteIntent(NotificationIntentInterceptor.createInterceptPendingIntent(
+ NotificationIntentInterceptor.IntentType.DELETE_INTENT, 0 /* intentId */, mMetadata,
+ intent));
+ return this;
+ }
+
+ @Override
@SuppressWarnings("deprecation")
public ChromeNotificationBuilder setPriorityBeforeO(int pri) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
@@ -309,4 +322,4 @@
public Notification build() {
return mBuilder.build();
}
-}
\ No newline at end of file
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationCompatBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationCompatBuilder.java
index 7f50125..552426e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationCompatBuilder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationCompatBuilder.java
@@ -31,6 +31,10 @@
}
mBuilder = new NotificationCompat.Builder(context, channelId);
mMetadata = metadata;
+ if (mMetadata != null) {
+ mBuilder.setDeleteIntent(
+ NotificationIntentInterceptor.getDefaultDeletePendingIntent(mMetadata));
+ }
}
@Override
@@ -145,6 +149,15 @@
}
@Override
+ public ChromeNotificationBuilder setDeleteIntent(PendingIntentProvider intent) {
+ assert (mMetadata != null);
+ mBuilder.setDeleteIntent(NotificationIntentInterceptor.createInterceptPendingIntent(
+ NotificationIntentInterceptor.IntentType.DELETE_INTENT, 0 /* intentId */, mMetadata,
+ intent));
+ return this;
+ }
+
+ @Override
public ChromeNotificationBuilder setPriorityBeforeO(int pri) {
mBuilder.setPriority(pri);
return this;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationIntentInterceptor.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationIntentInterceptor.java
index edbfba5..b07bc6d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationIntentInterceptor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationIntentInterceptor.java
@@ -11,6 +11,7 @@
import android.content.Intent;
import android.os.Build;
import android.support.annotation.IntDef;
+import android.support.annotation.Nullable;
import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
@@ -68,7 +69,7 @@
notificationType);
break;
case IntentType.DELETE_INTENT:
- // TODO(xingliu): Tracks dismiss event.
+ NotificationUmaTracker.getInstance().onNotificationDismiss(notificationType);
break;
case IntentType.ACTION_INTENT:
// TODO(xingliu): Tracks action click event.
@@ -82,20 +83,27 @@
private NotificationIntentInterceptor() {}
/**
- * Wraps the notification {@link PendingIntent }into another PendingIntent, to intercept clicks
+ * Wraps the notification {@link PendingIntent} into another PendingIntent, to intercept clicks
* and dismiss events for metrics purpose.
* @param intentType The type of the pending intent to intercept.
* @param intentId The unique ID of the {@link PendingIntent}, used to distinguish action
* intents.
* @param metadata The metadata including notification id, tag, type, etc.
- * @param pendingIntent The {@link PendingIntentProvider} of the notification that contains the
- * {@link Notification#contentIntent}.
+ * @param pendingIntentProvider Provides the {@link PendingIntent} to launch Chrome.
+ *
*/
public static PendingIntent createInterceptPendingIntent(@IntentType int intentType,
- int intentId, NotificationMetadata metadata, PendingIntentProvider pendingIntent) {
+ int intentId, NotificationMetadata metadata,
+ @Nullable PendingIntentProvider pendingIntentProvider) {
+ PendingIntent pendingIntent = null;
+ int flags = 0;
+ if (pendingIntentProvider != null) {
+ pendingIntent = pendingIntentProvider.getPendingIntent();
+ flags = pendingIntentProvider.getFlags();
+ }
Context applicationContext = ContextUtils.getApplicationContext();
Intent intent = new Intent(applicationContext, Receiver.class);
- intent.putExtra(EXTRA_PENDING_INTENT, pendingIntent.getPendingIntent());
+ intent.putExtra(EXTRA_PENDING_INTENT, pendingIntent);
intent.putExtra(EXTRA_INTENT_TYPE, intentType);
intent.putExtra(EXTRA_NOTIFICATION_TYPE, metadata.type);
@@ -106,8 +114,18 @@
}
// Use request code to distinguish different PendingIntents on Android.
int requestCode = computeHashCode(metadata, intentType, intentId);
- return PendingIntent.getBroadcast(
- applicationContext, requestCode, intent, pendingIntent.getFlags());
+ return PendingIntent.getBroadcast(applicationContext, requestCode, intent, flags);
+ }
+
+ /**
+ * Get the default delete PendingIntent used to track the notification metrics.
+ * @param metadata The metadata including notification id, tag, type, etc.
+ * @return The {@link PendingIntent} triggered when the user dismiss the notification.
+ */
+ public static PendingIntent getDefaultDeletePendingIntent(NotificationMetadata metadata) {
+ return NotificationIntentInterceptor.createInterceptPendingIntent(
+ NotificationIntentInterceptor.IntentType.DELETE_INTENT, 0 /* intentId */, metadata,
+ null /* pendingIntentProvider */);
}
// Launches the notification's pending intent, which will perform Chrome feature related tasks.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
index 227f8f4..e3eb308 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
@@ -116,6 +116,21 @@
.record(type);
}
+ /**
+ * Logs notification dismiss event the user swipes away the notification.
+ * @param type Type of the notification.
+ */
+ public void onNotificationDismiss(@SystemNotificationType int type) {
+ if (type == SystemNotificationType.UNKNOWN) return;
+
+ // TODO(xingliu): This may not work if Android kill Chrome before native library is loaded.
+ // Cache data in Android shared preference and flush them to native when available.
+ new CachedMetrics
+ .EnumeratedHistogramSample(
+ "Mobile.SystemNotification.Dismiss", SystemNotificationType.NUM_ENTRIES)
+ .record(type);
+ }
+
private void logNotificationShown(
@SystemNotificationType int type, @ChannelDefinitions.ChannelId String channelId) {
if (!mNotificationManager.areNotificationsEnabled()) {
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index cade26e4..609490b 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -52957,9 +52957,17 @@
enum="SystemNotificationType">
<owner>xingliu@chromium.org</owner>
<summary>
- Records when the type of notification when the user clicks the body of
- Android notification. This does not include clicks on notification action
- buttons.
+ Records the type of notification when the user clicks the body of Android
+ notification. This does not include clicks on notification action buttons.
+ </summary>
+</histogram>
+
+<histogram name="Mobile.SystemNotification.Dismiss"
+ enum="SystemNotificationType">
+ <owner>xingliu@chromium.org</owner>
+ <summary>
+ Records the type of notification when the user dismisses the Android
+ notification.
</summary>
</histogram>