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>