swipe down to open noti shade fling support

Bug: 136431648
Test: go/swipe-down-home-open-notishade
Change-Id: Idef337ae0977e8ec3fb6288eb0cc84fc48619ca1
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index ed6f599..19edc94 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -120,6 +120,8 @@
     private int mCurrentBoundedUserId = -1;
     private float mNavBarButtonAlpha;
     private boolean mInputFocusTransferStarted;
+    private float mInputFocusTransferStartY;
+    private long mInputFocusTransferStartMillis;
     private float mWindowCornerRadius;
     private boolean mSupportsRoundedCornersOnWindows;
     private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
@@ -180,12 +182,16 @@
                         int action = event.getActionMasked();
                         if (action == ACTION_DOWN) {
                             mInputFocusTransferStarted = true;
-
+                            mInputFocusTransferStartY = event.getY();
+                            mInputFocusTransferStartMillis = event.getEventTime();
+                            bar.onInputFocusTransfer(mInputFocusTransferStarted, 0 /* velocity */);
                         }
                         if (action == ACTION_UP || action == ACTION_CANCEL) {
                             mInputFocusTransferStarted = false;
+                            bar.onInputFocusTransfer(mInputFocusTransferStarted,
+                                    (event.getY() - mInputFocusTransferStartY)
+                                    / (event.getEventTime() - mInputFocusTransferStartMillis));
                         }
-                        bar.onInputFocusTransfer(mInputFocusTransferStarted);
                         event.recycle();
                     }
                 });
@@ -596,7 +602,7 @@
                 StatusBar bar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
                 if (bar != null) {
                     mInputFocusTransferStarted = false;
-                    bar.onInputFocusTransfer(false);
+                    bar.onInputFocusTransfer(false, 0 /* velocity */);
                 }
             });
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 53ce167..7723382 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -290,7 +290,11 @@
     private boolean mIsFullWidth;
     private boolean mBlockingExpansionForCurrentTouch;
 
-    private boolean mExpectingOpenPanelGesture;
+    /**
+     * Following variables maintain state of events when input focus transfer may occur.
+     */
+    private boolean mExpectingSynthesizedDown; // expecting to see synthesized DOWN event
+    private boolean mLastEventSynthesizedDown; // last event was synthesized DOWN event
 
     /**
      * Current dark amount that follows regular interpolation curve of animation.
@@ -1059,6 +1063,15 @@
             mDownY = event.getY();
             mCollapsedOnDown = isFullyCollapsed();
             mListenForHeadsUp = mCollapsedOnDown && mHeadsUpManager.hasPinnedHeadsUp();
+            if (mExpectingSynthesizedDown) {
+                mLastEventSynthesizedDown = true;
+            } else {
+                // down but not synthesized motion event.
+                mLastEventSynthesizedDown = false;
+            }
+        } else {
+            // not down event at all.
+            mLastEventSynthesizedDown = false;
         }
     }
 
@@ -1124,12 +1137,18 @@
             return false;
         }
 
-        initDownStates(event);
         // Make sure the next touch won't the blocked after the current ends.
         if (event.getAction() == MotionEvent.ACTION_UP
                 || event.getAction() == MotionEvent.ACTION_CANCEL) {
             mBlockingExpansionForCurrentTouch = false;
         }
+        // When touch focus transfer happens, ACTION_DOWN->ACTION_UP may happen immediately
+        // without any ACTION_MOVE event.
+        // In such case, simply expand the panel instead of being stuck at the bottom bar.
+        if (mLastEventSynthesizedDown && event.getAction() == MotionEvent.ACTION_UP) {
+            expand(true /* animate */);
+        }
+        initDownStates(event);
         if (!mIsExpanding && !shouldQuickSettingsIntercept(mDownX, mDownY, 0)
                 && mPulseExpansionHandler.onTouchEvent(event)) {
             // We're expanding all the other ones shouldn't get this anymore
@@ -1255,17 +1274,28 @@
         if (!isFullyCollapsed()) {
             return;
         }
-        mExpectingOpenPanelGesture = true;
+        mExpectingSynthesizedDown = true;
         onTrackingStarted();
     }
 
     /**
-     * Input focus transfer has already happened as this view decided to intercept
-     * very first down event.
+     * Called when this view is no longer waiting for input focus transfer.
+     *
+     * There are two scenarios behind this function call. First, input focus transfer
+     * has successfully happened and this view already received synthetic DOWN event.
+     * (mExpectingSynthesizedDown == false). Do nothing.
+     *
+     * Second, before input focus transfer finished, user may have lifted finger
+     * in previous window and this window never received synthetic DOWN event.
+     * (mExpectingSynthesizedDown == true).
+     * In this case, we use the velocity to trigger fling event.
+     *
+     * @param velocity unit is in px / millis
      */
-    public void stopWaitingForOpenPanelGesture() {
-        if (mExpectingOpenPanelGesture) {
-            mExpectingOpenPanelGesture = false;
+    public void stopWaitingForOpenPanelGesture(float velocity) {
+        if (mExpectingSynthesizedDown) {
+            mExpectingSynthesizedDown = false;
+            fling(velocity > 1f ? 1000f * velocity : 0, true /* animate */);
             onTrackingStopped(false);
         }
     }
@@ -1283,8 +1313,8 @@
 
     @Override
     protected boolean shouldGestureWaitForTouchSlop() {
-        if (mExpectingOpenPanelGesture) {
-            mExpectingOpenPanelGesture = false;
+        if (mExpectingSynthesizedDown) {
+            mExpectingSynthesizedDown = false;
             return false;
         }
         return isFullyCollapsed() || mBarState != StatusBarState.SHADE;
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 55f61fa..e075538 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -80,7 +80,6 @@
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
-import android.os.Debug;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -1930,7 +1929,7 @@
     /**
      * Called when another window is about to transfer it's input focus.
      */
-    public void onInputFocusTransfer(boolean start) {
+    public void onInputFocusTransfer(boolean start, float velocity) {
         if (!mCommandQueue.panelsEnabled()) {
             return;
         }
@@ -1938,7 +1937,7 @@
         if (start) {
             mNotificationPanel.startWaitingForOpenPanelGesture();
         } else {
-            mNotificationPanel.stopWaitingForOpenPanelGesture();
+            mNotificationPanel.stopWaitingForOpenPanelGesture(velocity);
         }
     }