From 9c84ea1ff0d93354b6eb378957b2e2f869537664 Mon Sep 17 00:00:00 2001
From: Vinit Nayak <peanutbutter@google.com>
Date: Fri, 19 Jun 2020 17:31:50 -0700
Subject: [PATCH] Show secondary home handle in immersive apps

If user is quickswitching, we show the secondary
home handle to let them know they can continue
quickswitching.
Also increased the secondary handle height region
to match that of the regular nav bar fragment,
the old height was causing too many false positives
for recents to think a touch was inside the app.

Bug: 158677967
Change-Id: I3a0e5bfa228eeb376a59ae4e82ed47589cbc51b0
---
 .../phone/NavigationBarFragment.java          | 33 +++++++++++----
 ...java => QuickswitchOrientedNavHandle.java} | 40 +++++++++++++++----
 2 files changed, 59 insertions(+), 14 deletions(-)
 rename packages/SystemUI/src/com/android/systemui/statusbar/phone/{VerticalNavigationHandle.java => QuickswitchOrientedNavHandle.java} (55%)

diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index df121f0faaf9..b04dbd7052ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -25,6 +25,7 @@ import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.containsType;
 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
 
@@ -221,13 +222,14 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
      * original handle hidden and we'll flip the visibilities once the
      * {@link #mTasksFrozenListener} fires
      */
-    private VerticalNavigationHandle mOrientationHandle;
+    private QuickswitchOrientedNavHandle mOrientationHandle;
     private WindowManager.LayoutParams mOrientationParams;
     private int mStartingQuickSwitchRotation;
     private int mCurrentRotation;
     private boolean mFixedRotationEnabled;
     private ViewTreeObserver.OnGlobalLayoutListener mOrientationHandleGlobalLayoutListener;
     private UiEventLogger mUiEventLogger;
+    private boolean mShowOrientedHandleForImmersiveMode;
 
     @com.android.internal.annotations.VisibleForTesting
     public enum NavBarActionEvent implements UiEventLogger.UiEventEnum {
@@ -299,6 +301,9 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
         @Override
         public void onQuickSwitchToNewTask(@Surface.Rotation int rotation) {
             mStartingQuickSwitchRotation = rotation;
+            if (rotation == -1) {
+                mShowOrientedHandleForImmersiveMode = false;
+            }
             orientSecondaryHomeHandle();
         }
 
@@ -602,7 +607,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
         getContext().getSystemService(DisplayManager.class)
                 .registerDisplayListener(this, new Handler(Looper.getMainLooper()));
 
-        mOrientationHandle = new VerticalNavigationHandle(getContext());
+        mOrientationHandle = new QuickswitchOrientedNavHandle(getContext());
 
         getBarTransitions().addDarkIntensityListener(mOrientationHandleIntensityListener);
         mOrientationParams = new WindowManager.LayoutParams(0, 0,
@@ -613,8 +618,11 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
                         | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                         | WindowManager.LayoutParams.FLAG_SLIPPERY,
                 PixelFormat.TRANSLUCENT);
+        mOrientationParams.setTitle("SecondaryHomeHandle" + getContext().getDisplayId());
+        mOrientationParams.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
         mWindowManager.addView(mOrientationHandle, mOrientationParams);
         mOrientationHandle.setVisibility(View.GONE);
+        mOrientationParams.setFitInsetsTypes(0 /* types*/);
         mOrientationHandleGlobalLayoutListener =
                 () -> {
                     if (mStartingQuickSwitchRotation == -1) {
@@ -651,22 +659,28 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
             int height = 0;
             int width = 0;
             Rect dispSize = mWindowManager.getCurrentWindowMetrics().getBounds();
+            mOrientationHandle.setDeltaRotation(deltaRotation);
             switch (deltaRotation) {
                 case Surface.ROTATION_90:
                 case Surface.ROTATION_270:
                     height = dispSize.height();
-                    width = getResources()
-                            .getDimensionPixelSize(R.dimen.navigation_bar_height);
+                    width = mNavigationBarView.getHeight();
                     break;
                 case Surface.ROTATION_180:
                 case Surface.ROTATION_0:
                     // TODO(b/152683657): Need to determine best UX for this
-                    resetSecondaryHandle();
-                    return;
+                    if (!mShowOrientedHandleForImmersiveMode) {
+                        resetSecondaryHandle();
+                        return;
+                    }
+                    width = dispSize.width();
+                    height = mNavigationBarView.getHeight();
+                    break;
             }
 
             mOrientationParams.gravity =
-                    deltaRotation == Surface.ROTATION_90 ? Gravity.LEFT : Gravity.RIGHT;
+                    deltaRotation == Surface.ROTATION_0 ? Gravity.BOTTOM :
+                            (deltaRotation == Surface.ROTATION_90 ? Gravity.LEFT : Gravity.RIGHT);
             mOrientationParams.height = height;
             mOrientationParams.width = width;
             mWindowManager.updateViewLayout(mOrientationHandle, mOrientationParams);
@@ -768,6 +782,11 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
                 && mNavigationBarWindowState != state) {
             mNavigationBarWindowState = state;
             updateSystemUiStateFlags(-1);
+            mShowOrientedHandleForImmersiveMode = state == WINDOW_STATE_HIDDEN;
+            if (mOrientationHandle != null
+                    && mStartingQuickSwitchRotation != -1) {
+                orientSecondaryHomeHandle();
+            }
             if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
 
             if (mNavigationBarView != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickswitchOrientedNavHandle.java
similarity index 55%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickswitchOrientedNavHandle.java
index 0cdf1d32d6a0..fe74677a8d51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickswitchOrientedNavHandle.java
@@ -19,19 +19,25 @@ package com.android.systemui.statusbar.phone;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.RectF;
+import android.view.Surface;
 
 import com.android.systemui.R;
 
 /** Temporarily shown view when using QuickSwitch to switch between apps of different rotations */
-public class VerticalNavigationHandle extends NavigationHandle {
+public class QuickswitchOrientedNavHandle extends NavigationHandle {
     private final int mWidth;
     private final RectF mTmpBoundsRectF = new RectF();
+    private @Surface.Rotation int mDeltaRotation;
 
-    public VerticalNavigationHandle(Context context) {
+    public QuickswitchOrientedNavHandle(Context context) {
         super(context);
         mWidth = context.getResources().getDimensionPixelSize(R.dimen.navigation_home_handle_width);
     }
 
+    void setDeltaRotation(@Surface.Rotation int rotation) {
+        mDeltaRotation = rotation;
+    }
+
     @Override
     protected void onDraw(Canvas canvas) {
         canvas.drawRoundRect(computeHomeHandleBounds(), mRadius, mRadius, mPaint);
@@ -42,12 +48,32 @@ public class VerticalNavigationHandle extends NavigationHandle {
         int top;
         int bottom;
         int right;
-        int topStart = getLocationOnScreen()[1];
         int radiusOffset = mRadius * 2;
-        right = getWidth() - mBottom;
-        top = getHeight() / 2 - (mWidth / 2) - (topStart / 2);
-        left = getWidth() - mBottom - radiusOffset;
-        bottom = top + mWidth;
+        int topStart = getLocationOnScreen()[1];
+
+        switch (mDeltaRotation) {
+            default:
+            case Surface.ROTATION_0:
+            case Surface.ROTATION_180:
+                int height = mRadius * 2;
+                left = getWidth() / 2 - mWidth / 2;
+                top = (getHeight() - mBottom - height);
+                right = getWidth() / 2 + mWidth / 2;
+                bottom = top + height;
+                break;
+            case Surface.ROTATION_90:
+                left = mBottom;
+                right = left + radiusOffset;
+                top = getHeight() / 2 - (mWidth / 2) - (topStart / 2);
+                bottom = top + mWidth;
+                break;
+            case Surface.ROTATION_270:
+                right = getWidth() - mBottom;
+                left = right - radiusOffset;
+                top = getHeight() / 2 - (mWidth / 2) - (topStart / 2);
+                bottom = top + mWidth;
+                break;
+        }
         mTmpBoundsRectF.set(left, top, right, bottom);
         return mTmpBoundsRectF;
     }
-- 
GitLab