Merge "Revert "Revert "Allow pulling down the status bar in visual immersive mode""" into sc-dev
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 779ba1c..8465889 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_UP;
 import static android.view.WindowInsets.Type.systemBars;
 
 import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
@@ -29,6 +32,7 @@
 import android.view.Display;
 import android.view.DisplayCutout;
 import android.view.Gravity;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.WindowInsets;
 import android.widget.FrameLayout;
@@ -49,6 +53,8 @@
     private int mRightInset = 0;
     private int mTopInset = 0;
 
+    private float mTouchDownY = 0;
+
     public StatusBarWindowView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -67,6 +73,28 @@
         return windowInsets;
     }
 
+    /**
+     * This is specifically for pulling down the status bar as a consistent motion in the visual
+     * immersive mode. In the visual immersive mode, after the system detects a system gesture
+     * motion from the top, we show permanent bars, and then forward the touch events from the
+     * focused window to the status bar window. However, since the first relayed event is out of
+     * bound of the status bar view, in order for the touch event to be correctly dispatched down,
+     * we jot down the position Y of the initial touch down event, offset it to 0 in the y-axis,
+     * and calculate the movement based on first touch down position.
+     */
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == ACTION_DOWN && ev.getRawY() > getHeight()) {
+            mTouchDownY = ev.getRawY();
+            ev.setLocation(ev.getRawX(), mTopInset);
+        } else if (ev.getAction() == ACTION_MOVE && mTouchDownY != 0) {
+            ev.setLocation(ev.getRawX(), mTopInset + ev.getRawY() - mTouchDownY);
+        } else if (ev.getAction() == ACTION_UP) {
+            mTouchDownY = 0;
+        }
+        return super.dispatchTouchEvent(ev);
+    }
+
     private void applyMargins() {
         final int count = getChildCount();
         for (int i = 0; i < count; i++) {
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 30151c3..70f2d64 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2420,6 +2420,15 @@
         } else {
             // Restore visibilities and positions of system bars.
             controlTarget.showInsets(Type.statusBars() | Type.navigationBars(), false);
+            // To further allow the pull-down-from-the-top gesture to pull down the notification
+            // shade as a consistent motion, we reroute the touch events here from the currently
+            // touched window to the status bar after making it visible.
+            if (swipeTarget == mStatusBar) {
+                final boolean transferred = mStatusBar.transferTouch();
+                if (!transferred) {
+                    Slog.i(TAG, "Could not transfer touch to the status bar");
+                }
+            }
         }
         mImmersiveModeConfirmation.confirmCurrentPrompt();
     }