Add rank & count event to notification clicks and dismisses

For click/action click/dismiss, passing rank(0-based) and
count at the time of the actions to events.

Bug: 70724602
Test: runtest systemui-notification
Test: atest packages/SystemUI/tests/src/com/android/systemui/statusbar/notification
Change-Id: I07c440f84ccb745f744eb4e317881b72d2b41683
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 2b7221a..159d49b 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -54,12 +54,13 @@
     void onPanelHidden();
     // Mark current notifications as "seen" and stop ringing, vibrating, blinking.
     void clearNotificationEffects();
-    void onNotificationClick(String key);
-    void onNotificationActionClick(String key, int actionIndex);
+    void onNotificationClick(String key, in NotificationVisibility nv);
+    void onNotificationActionClick(String key, int actionIndex, in NotificationVisibility nv);
     void onNotificationError(String pkg, String tag, int id,
             int uid, int initialPid, String message, int userId);
     void onClearAllNotifications(int userId);
-    void onNotificationClear(String pkg, String tag, int id, int userId, String key, int dismissalSurface);
+    void onNotificationClear(String pkg, String tag, int id, int userId, String key,
+            int dismissalSurface, in NotificationVisibility nv);
     void onNotificationVisibilityChanged( in NotificationVisibility[] newlyVisibleKeys,
             in NotificationVisibility[] noLongerVisibleKeys);
     void onNotificationExpansionChanged(in String key, in boolean userAction, in boolean expanded);
diff --git a/core/java/com/android/internal/statusbar/NotificationVisibility.java b/core/java/com/android/internal/statusbar/NotificationVisibility.java
index 2139ad0..7fe440c 100644
--- a/core/java/com/android/internal/statusbar/NotificationVisibility.java
+++ b/core/java/com/android/internal/statusbar/NotificationVisibility.java
@@ -32,6 +32,7 @@
 
     public String key;
     public int rank;
+    public int count;
     public boolean visible = true;
     /*package*/ int id;
 
@@ -39,10 +40,11 @@
         id = sNexrId++;
     }
 
-    private NotificationVisibility(String key, int rank, boolean visibile) {
+    private NotificationVisibility(String key, int rank, int count, boolean visibile) {
         this();
         this.key = key;
         this.rank = rank;
+        this.count = count;
         this.visible = visibile;
     }
 
@@ -51,13 +53,14 @@
         return "NotificationVisibility(id=" + id
                 + "key=" + key
                 + " rank=" + rank
+                + " count=" + count
                 + (visible?" visible":"")
                 + " )";
     }
 
     @Override
     public NotificationVisibility clone() {
-        return obtain(this.key, this.rank, this.visible);
+        return obtain(this.key, this.rank, this.count, this.visible);
     }
 
     @Override
@@ -85,12 +88,14 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeString(this.key);
         out.writeInt(this.rank);
+        out.writeInt(this.count);
         out.writeInt(this.visible ? 1 : 0);
     }
 
     private void readFromParcel(Parcel in) {
         this.key = in.readString();
         this.rank = in.readInt();
+        this.count = in.readInt();
         this.visible = in.readInt() != 0;
     }
 
@@ -98,10 +103,11 @@
      * Return a new NotificationVisibility instance from the global pool. Allows us to
      * avoid allocating new objects in many cases.
      */
-    public static NotificationVisibility obtain(String key, int rank, boolean visible) {
+    public static NotificationVisibility obtain(String key, int rank, int count, boolean visible) {
         NotificationVisibility vo = obtain();
         vo.key = key;
         vo.rank = rank;
+        vo.count = count;
         vo.visible = visible;
         return vo;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index ab46b39..3b8f15e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -509,6 +509,14 @@
         return null;
     }
 
+    public int getRank(String key) {
+        if (mRankingMap != null) {
+            getRanking(key, mTmpRanking);
+            return mTmpRanking.getRank();
+        }
+        return 0;
+    }
+
     public boolean shouldHide(String key) {
         if (mRankingMap != null) {
             getRanking(key, mTmpRanking);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
index 849cfdd..c5ab057 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
@@ -46,6 +46,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.NotificationVisibility;
 import com.android.internal.util.NotificationMessagingUtil;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.Dependency;
@@ -367,6 +368,10 @@
     }
 
     public void performRemoveNotification(StatusBarNotification n) {
+        final int rank = mNotificationData.getRank(n.getKey());
+        final int count = mNotificationData.getActiveNotifications().size();
+        final NotificationVisibility nv = NotificationVisibility.obtain(n.getKey(), rank, count,
+                true);
         NotificationData.Entry entry = mNotificationData.get(n.getKey());
         mRemoteInputManager.onPerformRemoveNotification(n, entry);
         final String pkg = n.getPackageName();
@@ -380,7 +385,7 @@
             } else if (mListContainer.hasPulsingNotifications()) {
                 dismissalSurface = NotificationStats.DISMISSAL_AOD;
             }
-            mBarService.onNotificationClear(pkg, tag, id, userId, n.getKey(), dismissalSurface);
+            mBarService.onNotificationClear(pkg, tag, id, userId, n.getKey(), dismissalSurface, nv);
             removeNotification(n.getKey(), null);
 
         } catch (RemoteException ex) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index e24bf67..c4cc494 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -38,6 +38,7 @@
 import android.widget.Toast;
 
 import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.NotificationVisibility;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
@@ -129,8 +130,13 @@
                     }
                 }
                 if (notificationKey != null) {
+                    final int count =
+                            mEntryManager.getNotificationData().getActiveNotifications().size();
+                    final int rank = mEntryManager.getNotificationData().getRank(notificationKey);
+                    final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
+                            rank, count, true);
                     try {
-                        mBarService.onNotificationClick(notificationKey);
+                        mBarService.onNotificationClick(notificationKey, nv);
                     } catch (RemoteException e) {
                         /* ignore */
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLogger.java
index 4225f83..01ec461 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLogger.java
@@ -107,7 +107,7 @@
                 NotificationData.Entry entry = activeNotifications.get(i);
                 String key = entry.notification.getKey();
                 boolean isVisible = mListContainer.isInVisibleLocation(entry.row);
-                NotificationVisibility visObj = NotificationVisibility.obtain(key, i, isVisible);
+                NotificationVisibility visObj = NotificationVisibility.obtain(key, i, N, isVisible);
                 boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(visObj);
                 if (isVisible) {
                     // Build new set of visible notifications.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 3c480d8..a333654 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -39,6 +39,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.statusbar.policy.RemoteInputView;
@@ -132,8 +133,11 @@
                 ViewGroup actionGroup = (ViewGroup) parent;
                 index = actionGroup.indexOfChild(view);
             }
+            final int count = mEntryManager.getNotificationData().getActiveNotifications().size();
+            final int rank = mEntryManager.getNotificationData().getRank(key);
+            final NotificationVisibility nv = NotificationVisibility.obtain(key, rank, count, true);
             try {
-                mBarService.onNotificationActionClick(key, index);
+                mBarService.onNotificationActionClick(key, index, nv);
             } catch (RemoteException e) {
                 // Ignore
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 27e5732b..67da2ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -131,6 +131,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.NotificationVisibility;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.MessagingGroup;
@@ -5117,8 +5118,13 @@
                     collapseOnMainThread();
                 }
 
+                final int count =
+                        mEntryManager.getNotificationData().getActiveNotifications().size();
+                final int rank = mEntryManager.getNotificationData().getRank(notificationKey);
+                final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
+                        rank, count, true);
                 try {
-                    mBarService.onNotificationClick(notificationKey);
+                    mBarService.onNotificationClick(notificationKey, nv);
                 } catch (RemoteException ex) {
                     // system process is dead if we're here.
                 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLoggerTest.java
index 726810e..14fada5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLoggerTest.java
@@ -93,7 +93,7 @@
         waitForUiOffloadThread();
 
         NotificationVisibility[] newlyVisibleKeys = {
-                NotificationVisibility.obtain(mEntry.key, 0, true)
+                NotificationVisibility.obtain(mEntry.key, 0, 1, true)
         };
         NotificationVisibility[] noLongerVisibleKeys = {};
         verify(mBarService).onNotificationVisibilityChanged(newlyVisibleKeys, noLongerVisibleKeys);
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 93de08c..1f1ed59 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5664,6 +5664,10 @@
     // OS: P
     BLUETOOTH_FRAGMENT = 1390;
 
+    // This value should never appear in log outputs - it is reserved for
+    // internal platform metrics use.
+    NOTIFICATION_SHADE_COUNT = 1395;
+
     // ---- End P Constants, all P constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 48bb409..2465ba2 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -72,11 +72,11 @@
 # when notifications are expanded, or contracted
 27511 notification_expansion (key|3),(user_action|1),(expanded|1),(lifespan|1),(freshness|1),(exposure|1)
 # when a notification has been clicked
-27520 notification_clicked (key|3),(lifespan|1),(freshness|1),(exposure|1)
+27520 notification_clicked (key|3),(lifespan|1),(freshness|1),(exposure|1),(rank|1),(count|1)
 # when a notification action button has been clicked
-27521 notification_action_clicked (key|3),(action_index|1),(lifespan|1),(freshness|1),(exposure|1)
+27521 notification_action_clicked (key|3),(action_index|1),(lifespan|1),(freshness|1),(exposure|1),(rank|1),(count|1)
 # when a notification has been canceled
-27530 notification_canceled (key|3),(reason|1),(lifespan|1),(freshness|1),(exposure|1),(listener|3)
+27530 notification_canceled (key|3),(reason|1),(lifespan|1),(freshness|1),(exposure|1),(rank|1),(count|1),(listener|3)
 # replaces 27510 with a row per notification
 27531 notification_visibility (key|3),(visibile|1),(lifespan|1),(freshness|1),(exposure|1),(rank|1)
 # a notification emited noise, vibration, or light
diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java
index b61a27a..8be8450 100644
--- a/services/core/java/com/android/server/notification/NotificationDelegate.java
+++ b/services/core/java/com/android/server/notification/NotificationDelegate.java
@@ -23,11 +23,14 @@
 public interface NotificationDelegate {
     void onSetDisabled(int status);
     void onClearAll(int callingUid, int callingPid, int userId);
-    void onNotificationClick(int callingUid, int callingPid, String key);
-    void onNotificationActionClick(int callingUid, int callingPid, String key, int actionIndex);
+    void onNotificationClick(int callingUid, int callingPid, String key,
+            NotificationVisibility nv);
+    void onNotificationActionClick(int callingUid, int callingPid, String key, int actionIndex,
+            NotificationVisibility nv);
     void onNotificationClear(int callingUid, int callingPid,
             String pkg, String tag, int id, int userId, String key,
-            @NotificationStats.DismissalSurface int dismissalSurface);
+            @NotificationStats.DismissalSurface int dismissalSurface,
+            NotificationVisibility nv);
     void onNotificationError(int callingUid, int callingPid,
             String pkg, String tag, int id,
             int uid, int initialPid, String message, int userId);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d5b2ee3..6fce9c5 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -693,7 +693,7 @@
         }
 
         @Override
-        public void onNotificationClick(int callingUid, int callingPid, String key) {
+        public void onNotificationClick(int callingUid, int callingPid, String key, NotificationVisibility nv) {
             exitIdle();
             synchronized (mNotificationLock) {
                 NotificationRecord r = mNotificationsByKey.get(key);
@@ -704,22 +704,26 @@
                 final long now = System.currentTimeMillis();
                 MetricsLogger.action(r.getLogMaker(now)
                         .setCategory(MetricsEvent.NOTIFICATION_ITEM)
-                        .setType(MetricsEvent.TYPE_ACTION));
+                        .setType(MetricsEvent.TYPE_ACTION)
+                        .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
+                        .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count));
                 EventLogTags.writeNotificationClicked(key,
-                        r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
+                        r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
+                        nv.rank, nv.count);
 
                 StatusBarNotification sbn = r.sbn;
                 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
                         sbn.getId(), Notification.FLAG_AUTO_CANCEL,
                         Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
-                        REASON_CLICK, null);
+                        REASON_CLICK, nv.rank, nv.count, null);
+                nv.recycle();
                 reportUserInteraction(r);
             }
         }
 
         @Override
         public void onNotificationActionClick(int callingUid, int callingPid, String key,
-                int actionIndex) {
+                int actionIndex, NotificationVisibility nv) {
             exitIdle();
             synchronized (mNotificationLock) {
                 NotificationRecord r = mNotificationsByKey.get(key);
@@ -731,9 +735,13 @@
                 MetricsLogger.action(r.getLogMaker(now)
                         .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
                         .setType(MetricsEvent.TYPE_ACTION)
-                        .setSubtype(actionIndex));
+                        .setSubtype(actionIndex)
+                        .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
+                        .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count));
                 EventLogTags.writeNotificationActionClicked(key, actionIndex,
-                        r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
+                        r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
+                        nv.rank, nv.count);
+                nv.recycle();
                 reportUserInteraction(r);
             }
         }
@@ -741,7 +749,8 @@
         @Override
         public void onNotificationClear(int callingUid, int callingPid,
                 String pkg, String tag, int id, int userId, String key,
-                @NotificationStats.DismissalSurface int dismissalSurface) {
+                @NotificationStats.DismissalSurface int dismissalSurface,
+                NotificationVisibility nv) {
             synchronized (mNotificationLock) {
                 NotificationRecord r = mNotificationsByKey.get(key);
                 if (r != null) {
@@ -750,7 +759,8 @@
             }
             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
                     Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
-                    true, userId, REASON_CANCEL, null);
+                    true, userId, REASON_CANCEL, nv.rank, nv.count,null);
+            nv.recycle();
         }
 
         @Override
@@ -820,7 +830,7 @@
                             mMetricsLogger.write(logMaker);
                         }
                     }
-                    r.setVisibility(true, nv.rank);
+                    r.setVisibility(true, nv.rank, nv.count);
                     nv.recycle();
                 }
                 // Note that we might receive this event after notifications
@@ -830,7 +840,7 @@
                 for (NotificationVisibility nv : noLongerVisibleKeys) {
                     NotificationRecord r = mNotificationsByKey.get(nv.key);
                     if (r == null) continue;
-                    r.setVisibility(false, nv.rank);
+                    r.setVisibility(false, nv.rank, nv.count);
                     nv.recycle();
                 }
             }
@@ -5297,6 +5307,12 @@
     @GuardedBy("mNotificationLock")
     private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
             boolean wasPosted, String listenerName) {
+        cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName);
+    }
+
+    @GuardedBy("mNotificationLock")
+    private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
+            int rank, int count, boolean wasPosted, String listenerName) {
         final String canceledKey = r.getKey();
 
         // Record caller.
@@ -5398,12 +5414,18 @@
         mArchive.record(r.sbn);
 
         final long now = System.currentTimeMillis();
-        MetricsLogger.action(r.getLogMaker(now)
+        final LogMaker logMaker = r.getLogMaker(now)
                 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
                 .setType(MetricsEvent.TYPE_DISMISS)
-                .setSubtype(reason));
+                .setSubtype(reason);
+        if (rank != -1 && count != -1) {
+            logMaker.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)
+                    .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count);
+        }
+        MetricsLogger.action(logMaker);
         EventLogTags.writeNotificationCanceled(canceledKey, reason,
-                r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), listenerName);
+                r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
+                rank, count, listenerName);
     }
 
     void revokeUriPermissions(NotificationRecord newRecord, NotificationRecord oldRecord) {
@@ -5438,6 +5460,18 @@
             final String pkg, final String tag, final int id,
             final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
             final int userId, final int reason, final ManagedServiceInfo listener) {
+        cancelNotification(callingUid, callingPid, pkg, tag, id, mustHaveFlags, mustNotHaveFlags,
+                sendDelete, userId, reason, -1 /* rank */, -1 /* count */, listener);
+    }
+
+    /**
+     * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
+     * and none of the {@code mustNotHaveFlags}.
+     */
+    void cancelNotification(final int callingUid, final int callingPid,
+            final String pkg, final String tag, final int id,
+            final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
+            final int userId, final int reason, int rank, int count, final ManagedServiceInfo listener) {
 
         // In enqueueNotificationInternal notifications are added by scheduling the
         // work on the worker handler. Hence, we also schedule the cancel on this
@@ -5471,7 +5505,7 @@
 
                         // Cancel the notification.
                         boolean wasPosted = removeFromNotificationListsLocked(r);
-                        cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
+                        cancelNotificationLocked(r, sendDelete, reason, rank, count, wasPosted, listenerName);
                         cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
                                 sendDelete, null);
                         updateLightsLocked();
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 9745be3..57af2ce 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -778,14 +778,15 @@
     /**
      * Set the visibility of the notification.
      */
-    public void setVisibility(boolean visible, int rank) {
+    public void setVisibility(boolean visible, int rank, int count) {
         final long now = System.currentTimeMillis();
         mVisibleSinceMs = visible ? now : mVisibleSinceMs;
         stats.onVisibilityChanged(visible);
         MetricsLogger.action(getLogMaker(now)
                 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
                 .setType(visible ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE)
-                .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank));
+                .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)
+                .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count));
         if (visible) {
             setSeen();
             MetricsLogger.histogram(mContext, "note_freshness", getFreshnessMs(now));
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 36fa868..738b0ca 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -1000,27 +1000,27 @@
     }
 
     @Override
-    public void onNotificationClick(String key) {
+    public void onNotificationClick(String key, NotificationVisibility nv) {
         enforceStatusBarService();
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
         long identity = Binder.clearCallingIdentity();
         try {
-            mNotificationDelegate.onNotificationClick(callingUid, callingPid, key);
+            mNotificationDelegate.onNotificationClick(callingUid, callingPid, key, nv);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
     }
 
     @Override
-    public void onNotificationActionClick(String key, int actionIndex) {
+    public void onNotificationActionClick(String key, int actionIndex, NotificationVisibility nv) {
         enforceStatusBarService();
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
         long identity = Binder.clearCallingIdentity();
         try {
             mNotificationDelegate.onNotificationActionClick(callingUid, callingPid, key,
-                    actionIndex);
+                    actionIndex, nv);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -1044,14 +1044,14 @@
 
     @Override
     public void onNotificationClear(String pkg, String tag, int id, int userId, String key,
-            @NotificationStats.DismissalSurface int dismissalSurface) {
+            @NotificationStats.DismissalSurface int dismissalSurface, NotificationVisibility nv) {
         enforceStatusBarService();
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
         long identity = Binder.clearCallingIdentity();
         try {
-            mNotificationDelegate.onNotificationClear(
-                    callingUid, callingPid, pkg, tag, id, userId, key, dismissalSurface);
+            mNotificationDelegate.onNotificationClear(callingUid, callingPid, pkg, tag, id, userId,
+                    key, dismissalSurface, nv);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 9d5d263..1a9b7db 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -2335,7 +2335,7 @@
         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
         mService.addNotification(r);
 
-        NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 1, true);
+        final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 1, 2, true);
         mService.mNotificationDelegate.onNotificationVisibilityChanged(
                 new NotificationVisibility[] {nv}, new NotificationVisibility[]{});
         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasSeen());
@@ -2349,8 +2349,9 @@
         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
         mService.addNotification(r);
 
+        final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true);
         mService.mNotificationDelegate.onNotificationClear(mUid, 0, PKG, r.sbn.getTag(),
-                r.sbn.getId(), r.getUserId(), r.getKey(), NotificationStats.DISMISSAL_AOD);
+                r.sbn.getId(), r.getUserId(), r.getKey(), NotificationStats.DISMISSAL_AOD, nv);
         waitForIdle();
 
         assertEquals(NotificationStats.DISMISSAL_AOD, r.getStats().getDismissalSurface());