Use InteractionJankMonitor to instrument CUJs of NotificationShade

Instrument the CUJs of NotificationShade, including:
- Expand / collapse / scroll NotificationShade.
- Expand / collapse QS panel.
- Expand / collapse NotificationShade in lockscreen.

Will have a follow up cl for:
- Expand and swipe in NSSL.
- Headsup arriving / dismissing.
- Maybe clear animation?

Bug: 169220725
Bug: 169221093
Bug: 169220802
Bug: 169220995
Test: Manually
Change-Id: Ib5e003e1698132715820b539bbcf35012fe83547
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 500de2d..9320499 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.stack;
 
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING;
 import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
 import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
 import static com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.ANCHOR_SCROLLING;
@@ -73,6 +74,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.ColorUtils;
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.keyguard.KeyguardSliceView;
 import com.android.settingslib.Utils;
@@ -97,7 +99,6 @@
 import com.android.systemui.statusbar.notification.ShadeViewRefactor;
 import com.android.systemui.statusbar.notification.ShadeViewRefactor.RefactorComponent;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
@@ -260,6 +261,7 @@
     private boolean mDismissAllInProgress;
     private boolean mFadeNotificationsOnDismiss;
     private FooterDismissListener mFooterDismissListener;
+    private boolean mFlingAfterUpEvent;
 
     /**
      * Was the scroller scrolled to the top when the down motion was observed?
@@ -3789,6 +3791,13 @@
                             if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
                                 float currentOverScrollTop = getCurrentOverScrollAmount(true);
                                 if (currentOverScrollTop == 0.0f || initialVelocity > 0) {
+                                    mFlingAfterUpEvent = true;
+                                    setFinishScrollingCallback(() -> {
+                                        mFlingAfterUpEvent = false;
+                                        InteractionJankMonitor.getInstance()
+                                                .end(CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
+                                        setFinishScrollingCallback(null);
+                                    });
                                     fling(-initialVelocity);
                                 } else {
                                     onOverScrollFling(false, initialVelocity);
@@ -3840,6 +3849,10 @@
         return true;
     }
 
+    boolean isFlingAfterUpEvent() {
+        return mFlingAfterUpEvent;
+    }
+
     @ShadeViewRefactor(RefactorComponent.INPUT)
     protected boolean isInsideQsContainer(MotionEvent ev) {
         return ev.getY() < mQsContainer.getBottom();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 703c214..6820819 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -19,6 +19,7 @@
 import static android.service.notification.NotificationStats.DISMISSAL_SHADE;
 import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
 
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING;
 import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.OnEmptySpaceClickListener;
@@ -47,6 +48,7 @@
 import android.widget.FrameLayout;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEvent;
 import com.android.internal.logging.UiEventLogger;
@@ -1556,6 +1558,14 @@
             if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
                 mView.setCheckForLeaveBehind(true);
             }
+
+            // When swiping directly on the NSSL, this would only get an onTouchEvent.
+            // We log any touches other than down, which will be captured by onTouchEvent.
+            // In the intercept we only start tracing when it's not a down (otherwise that down
+            // would be duplicated when intercepted).
+            if (scrollWantsIt && ev.getActionMasked() != MotionEvent.ACTION_DOWN) {
+                InteractionJankMonitor.getInstance().begin(CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
+            }
             return swipeWantsIt || scrollWantsIt || expandWantsIt;
         }
 
@@ -1611,7 +1621,32 @@
             if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
                 mView.setCheckForLeaveBehind(true);
             }
+            traceJankOnTouchEvent(ev.getActionMasked(), scrollerWantsIt);
             return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt;
         }
+
+        private void traceJankOnTouchEvent(int action, boolean scrollerWantsIt) {
+            // Handle interaction jank monitor cases.
+            switch (action) {
+                case MotionEvent.ACTION_DOWN:
+                    if (scrollerWantsIt) {
+                        InteractionJankMonitor.getInstance()
+                                .begin(CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
+                    }
+                    break;
+                case MotionEvent.ACTION_UP:
+                    if (scrollerWantsIt && !mView.isFlingAfterUpEvent()) {
+                        InteractionJankMonitor.getInstance()
+                                .end(CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
+                    }
+                    break;
+                case MotionEvent.ACTION_CANCEL:
+                    if (scrollerWantsIt) {
+                        InteractionJankMonitor.getInstance()
+                                .cancel(CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
+                    }
+                    break;
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index cd9cc07..3f636ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -18,6 +18,8 @@
 
 import static android.view.View.GONE;
 
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE;
 import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
@@ -62,6 +64,7 @@
 import android.widget.TextView;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.LatencyTracker;
@@ -1139,6 +1142,7 @@
                     onQsExpansionStarted();
                     mInitialHeightOnTouch = mQsExpansionHeight;
                     mQsTracking = true;
+                    traceQsJank(true /* startTracing */, false /* wasCancelled */);
                     mNotificationStackScrollLayoutController.cancelLongPress();
                 }
                 break;
@@ -1170,6 +1174,7 @@
                         && shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, h)) {
                     mView.getParent().requestDisallowInterceptTouchEvent(true);
                     mQsTracking = true;
+                    traceQsJank(true /* startTracing */, false /* wasCancelled */);
                     onQsExpansionStarted();
                     notifyExpandingFinished();
                     mInitialHeightOnTouch = mQsExpansionHeight;
@@ -1202,6 +1207,19 @@
                 && x < stackScrollerX + mNotificationStackScrollLayoutController.getWidth();
     }
 
+    private void traceQsJank(boolean startTracing, boolean wasCancelled) {
+        InteractionJankMonitor monitor = InteractionJankMonitor.getInstance();
+        if (startTracing) {
+            monitor.begin(CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE);
+        } else {
+            if (wasCancelled) {
+                monitor.cancel(CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE);
+            } else {
+                monitor.end(CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE);
+            }
+        }
+    }
+
     private void initDownStates(MotionEvent event) {
         if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
             mOnlyAffordanceInThisMotion = false;
@@ -1315,9 +1333,9 @@
         final int action = event.getActionMasked();
         if (action == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f
                 && mBarState != KEYGUARD && !mQsExpanded && mQsExpansionEnabled) {
-
             // Down in the empty area while fully expanded - go to QS.
             mQsTracking = true;
+            traceQsJank(true /* startTracing */, false /* wasCancelled */);
             mConflictingQsExpansionGesture = true;
             onQsExpansionStarted();
             mInitialHeightOnTouch = mQsExpansionHeight;
@@ -1405,6 +1423,7 @@
             return;
         }
         mExpectingSynthesizedDown = true;
+        InteractionJankMonitor.getInstance().begin(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
         onTrackingStarted();
         updatePanelExpanded();
     }
@@ -1474,6 +1493,7 @@
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
                 mQsTracking = true;
+                traceQsJank(true /* startTracing */, false /* wasCancelled */);
                 mInitialTouchY = y;
                 mInitialTouchX = x;
                 onQsExpansionStarted();
@@ -1513,6 +1533,9 @@
                 if (fraction != 0f || y >= mInitialTouchY) {
                     flingQsWithCurrentVelocity(y,
                             event.getActionMasked() == MotionEvent.ACTION_CANCEL);
+                } else {
+                    traceQsJank(false /* startTracing */,
+                            event.getActionMasked() == MotionEvent.ACTION_CANCEL);
                 }
                 if (mQsVelocityTracker != null) {
                     mQsVelocityTracker.recycle();
@@ -1893,7 +1916,7 @@
      * @see #flingSettings(float, int, Runnable, boolean)
      */
     public void flingSettings(float vel, int type) {
-        flingSettings(vel, type, null, false /* isClick */);
+        flingSettings(vel, type, null /* onFinishRunnable */, false /* isClick */);
     }
 
     /**
@@ -1923,6 +1946,7 @@
             if (onFinishRunnable != null) {
                 onFinishRunnable.run();
             }
+            traceQsJank(false /* startTracing */, type != FLING_EXPAND /* wasCancelled */);
             return;
         }
 
@@ -1947,12 +1971,18 @@
             setQsExpansion((Float) animation.getAnimatedValue());
         });
         animator.addListener(new AnimatorListenerAdapter() {
+            private boolean mIsCanceled;
             @Override
             public void onAnimationStart(Animator animation) {
                 notifyExpandingStarted();
             }
 
             @Override
+            public void onAnimationCancel(Animator animation) {
+                mIsCanceled = true;
+            }
+
+            @Override
             public void onAnimationEnd(Animator animation) {
                 mAnimatingQS = false;
                 notifyExpandingFinished();
@@ -1961,6 +1991,7 @@
                 if (onFinishRunnable != null) {
                     onFinishRunnable.run();
                 }
+                traceQsJank(false /* startTracing */, mIsCanceled /* wasCancelled */);
             }
         });
         // Let's note that we're animating QS. Moving the animator here will cancel it immediately,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java
index bc80a1a..a4fc3a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java
@@ -49,6 +49,7 @@
 import android.view.WindowInsetsController;
 import android.widget.FrameLayout;
 
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.view.FloatingActionMode;
 import com.android.internal.widget.FloatingToolbar;
 import com.android.systemui.R;
@@ -145,6 +146,7 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         setWillNotDraw(!DEBUG);
+        InteractionJankMonitor.getInstance().init(this);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 6fa99ba..5a01f47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE;
 import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
 import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
 import static com.android.systemui.classifier.Classifier.UNLOCK;
@@ -40,6 +41,7 @@
 import android.view.ViewTreeObserver;
 import android.view.animation.Interpolator;
 
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.LatencyTracker;
 import com.android.systemui.DejankUtils;
@@ -109,6 +111,7 @@
     private boolean mMotionAborted;
     private boolean mUpwardsWhenThresholdReached;
     private boolean mAnimatingOnDown;
+    private boolean mHandlingPointerUp;
 
     private ValueAnimator mHeightAnimator;
     private ObjectAnimator mPeekAnimator;
@@ -356,6 +359,9 @@
 
     protected void startExpandMotion(float newX, float newY, boolean startTracking,
             float expandedHeight) {
+        if (!mHandlingPointerUp) {
+            InteractionJankMonitor.getInstance().begin(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
+        }
         mInitialOffsetOnTouch = expandedHeight;
         mInitialTouchY = newY;
         mInitialTouchX = newX;
@@ -571,6 +577,7 @@
             target = getMaxPanelHeight() - getClearAllHeightWithPadding();
         }
         if (target == mExpandedHeight || getOverExpansionAmount() > 0f && expand) {
+            InteractionJankMonitor.getInstance().end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
             notifyExpandingFinished();
             return;
         }
@@ -622,7 +629,12 @@
                 }
                 setAnimator(null);
                 if (!mCancelled) {
+                    InteractionJankMonitor.getInstance()
+                            .end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
                     notifyExpandingFinished();
+                } else {
+                    InteractionJankMonitor.getInstance()
+                            .cancel(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
                 }
                 notifyBarPanelExpansionChanged();
             }
@@ -1272,7 +1284,9 @@
                         final float newY = event.getY(newIndex);
                         final float newX = event.getX(newIndex);
                         mTrackingPointer = event.getPointerId(newIndex);
+                        mHandlingPointerUp = true;
                         startExpandMotion(newX, newY, true /* startTracking */, mExpandedHeight);
+                        mHandlingPointerUp = false;
                     }
                     break;
                 case MotionEvent.ACTION_POINTER_DOWN:
@@ -1330,6 +1344,12 @@
                 case MotionEvent.ACTION_CANCEL:
                     addMovement(event);
                     endMotionEvent(event, x, y, false /* forceCancel */);
+                    InteractionJankMonitor monitor = InteractionJankMonitor.getInstance();
+                    if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+                        monitor.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
+                    } else {
+                        monitor.cancel(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
+                    }
                     break;
             }
             return !mGestureWaitForTouchSlop || mTracking;