Ime in gestural mode will have ime switcher and down arrow

When in gestural mode, the navigation bar will inset the ime window
higher to raise up revealing the original height of the navigation bar.
In place will be the (alt) back button (pointing down), the handle and
ime switcher (if should be shown).

Fixes: 128928130
Bug: 113952590
Bug: 112934365
Test: manual
Change-Id: I28cc4def846cb09eb2d7ab00d12561f0c198dbbc
(cherry picked from commit f03c3a639893b9274a87ae6706f5214d9d43cc40)
diff --git a/packages/SystemUI/res/layout/contextual.xml b/packages/SystemUI/res/layout/contextual.xml
index c8f0a24..9b6ccae 100644
--- a/packages/SystemUI/res/layout/contextual.xml
+++ b/packages/SystemUI/res/layout/contextual.xml
@@ -37,16 +37,10 @@
         android:paddingStart="@dimen/navigation_key_padding"
         android:paddingEnd="@dimen/navigation_key_padding"
     />
-    <com.android.systemui.statusbar.policy.KeyButtonView
-        android:id="@+id/ime_switcher"
+    <include layout="@layout/ime_switcher"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:layout_weight="0"
-        android:scaleType="center"
         android:visibility="invisible"
-        android:contentDescription="@string/accessibility_ime_switch_button"
-        android:paddingStart="@dimen/navigation_key_padding"
-        android:paddingEnd="@dimen/navigation_key_padding"
     />
     <com.android.systemui.statusbar.policy.KeyButtonView
         android:id="@+id/rotate_suggestion"
diff --git a/packages/SystemUI/res/layout/home_handle.xml b/packages/SystemUI/res/layout/home_handle.xml
index d950f39..7c5db10 100644
--- a/packages/SystemUI/res/layout/home_handle.xml
+++ b/packages/SystemUI/res/layout/home_handle.xml
@@ -21,5 +21,7 @@
     android:layout_width="@dimen/navigation_home_handle_width"
     android:layout_height="match_parent"
     android:layout_weight="0"
+    android:paddingStart="@dimen/navigation_key_padding"
+    android:paddingEnd="@dimen/navigation_key_padding"
     />
 
diff --git a/packages/SystemUI/res/layout/ime_switcher.xml b/packages/SystemUI/res/layout/ime_switcher.xml
new file mode 100644
index 0000000..7710b25
--- /dev/null
+++ b/packages/SystemUI/res/layout/ime_switcher.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<com.android.systemui.statusbar.policy.KeyButtonView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/ime_switcher"
+    android:layout_width="@dimen/navigation_key_width"
+    android:layout_height="match_parent"
+    android:layout_weight="0"
+    android:contentDescription="@string/accessibility_ime_switch_button"
+    android:scaleType="center"
+    android:paddingStart="@dimen/navigation_key_padding"
+    android:paddingEnd="@dimen/navigation_key_padding"
+    />
diff --git a/packages/SystemUI/res/layout/menu_ime.xml b/packages/SystemUI/res/layout/menu_ime.xml
index 8a3a0b1..24374e8 100644
--- a/packages/SystemUI/res/layout/menu_ime.xml
+++ b/packages/SystemUI/res/layout/menu_ime.xml
@@ -35,13 +35,13 @@
         android:visibility="invisible"
         android:contentDescription="@string/accessibility_menu"
         />
-    <com.android.systemui.statusbar.policy.KeyButtonView
-        android:id="@+id/ime_switcher"
+    <include layout="@layout/ime_switcher"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:visibility="invisible"
-        android:contentDescription="@string/accessibility_ime_switch_button"
         android:scaleType="centerInside"
+        android:visibility="invisible"
+        android:paddingStart="0dp"
+        android:paddingEnd="0dp"
         />
     <com.android.systemui.statusbar.policy.KeyButtonView
         android:id="@+id/rotate_suggestion"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index b0afe75..ce04638 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -330,7 +330,7 @@
     <!-- Nav bar button default ordering/layout -->
     <string name="config_navBarLayout" translatable="false">left[.5W],back[1WC];home;recent[1WC],right[.5W]</string>
     <string name="config_navBarLayoutQuickstep" translatable="false">back[1.7WC];home;contextual[1.7WC]</string>
-    <string name="config_navBarLayoutHandle" translatable="false">";home_handle;"</string>
+    <string name="config_navBarLayoutHandle" translatable="false">back[1.7WC];home_handle;ime_switcher[1.7WC]</string>
 
     <bool name="quick_settings_show_full_alarm">false</bool>
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
index 5dded52..541c142 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
@@ -51,6 +51,9 @@
      * Reload the drawable from resource id, should reapply the previous dark intensity.
      */
     public void updateIcon() {
+        if (getCurrentView() == null || !getCurrentView().isAttachedToWindow()) {
+            return;
+        }
         final KeyButtonDrawable currentDrawable = getImageDrawable();
         KeyButtonDrawable drawable = getNewDrawable();
         if (currentDrawable != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java
index 38df17a..02b660f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java
@@ -112,23 +112,24 @@
      * their icons for their buttons.
      */
     public void updateIcons() {
-        if (getCurrentView() == null || !getCurrentView().isAttachedToWindow()) {
-            return;
-        }
         for (ButtonData data : mButtonData) {
             data.button.updateIcon();
         }
     }
 
     public void dump(PrintWriter pw) {
+        View view = getCurrentView();
         pw.println("ContextualButtonGroup {");
         pw.println("      getVisibleContextButton(): " + getVisibleContextButton());
         pw.println("      isVisible(): " + isVisible());
+        pw.println("      attached(): " + (view != null && view.isAttachedToWindow()));
         pw.println("      mButtonData [ ");
         for (int i = mButtonData.size() - 1; i >= 0; --i) {
             final ButtonData data = mButtonData.get(i);
+            view = data.button.getCurrentView();
             pw.println("            " + i + ": markedVisible=" + data.markedVisible
                     + " visible=" + data.button.getVisibility()
+                    + " attached=" + (view != null && view.isAttachedToWindow())
                     + " alpha=" + data.button.getAlpha());
         }
         pw.println("      ]");
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 3dcadf1..6729f9f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -202,7 +202,9 @@
         @Override
         public void onBackButtonAlphaChanged(float alpha, boolean animate) {
             final ButtonDispatcher backButton = mNavigationBarView.getBackButton();
-            if (QuickStepContract.isGesturalMode(getContext())) {
+            final boolean useAltBack =
+                    (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
+            if (QuickStepContract.isGesturalMode(getContext()) && !useAltBack) {
                 // If property was changed to hide/show back button, going home will trigger
                 // launcher to to change the back button alpha to reflect property change
                 backButton.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 26aa617..a522ed1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -68,6 +68,7 @@
     public static final String LEFT = "left";
     public static final String RIGHT = "right";
     public static final String CONTEXTUAL = "contextual";
+    public static final String IME_SWITCHER = "ime_switcher";
 
     public static final String GRAVITY_SEPARATOR = ";";
     public static final String BUTTON_SEPARATOR = ",";
@@ -164,17 +165,21 @@
     @Override
     public void onTuningChanged(String key, String newValue) {
         if (NAV_BAR_VIEWS.equals(key)) {
-            if (!Objects.equals(mCurrentLayout, newValue)) {
-                mUsingCustomLayout = newValue != null;
-                clearViews();
-                inflateLayout(newValue);
-            }
+            setNavigationBarLayout(newValue);
         } else if (NAV_BAR_LEFT.equals(key) || NAV_BAR_RIGHT.equals(key)) {
             clearViews();
             inflateLayout(mCurrentLayout);
         }
     }
 
+    public void setNavigationBarLayout(String layoutValue) {
+        if (!Objects.equals(mCurrentLayout, layoutValue)) {
+            mUsingCustomLayout = layoutValue != null;
+            clearViews();
+            inflateLayout(layoutValue);
+        }
+    }
+
     public void onLikelyDefaultLayoutChange() {
         // Don't override custom layouts
         if (mUsingCustomLayout) return;
@@ -401,6 +406,8 @@
             v = inflater.inflate(R.layout.contextual, parent, false);
         } else if (HOME_HANDLE.equals(button)) {
             v = inflater.inflate(R.layout.home_handle, parent, false);
+        } else if (IME_SWITCHER.equals(button)) {
+            v = inflater.inflate(R.layout.ime_switcher, parent, false);
         } else if (button.startsWith(KEY)) {
             String uri = extractImage(button);
             int code = extractKeycode(button);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 7abdbd0..e2a63cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -21,7 +21,6 @@
 
 import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
-import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAV_BAR_VIEWS;
 
 import android.animation.LayoutTransition;
 import android.animation.LayoutTransition.TransitionListener;
@@ -35,6 +34,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ParceledListSlice;
 import android.content.res.Configuration;
 import android.graphics.Canvas;
 import android.graphics.Point;
@@ -48,6 +48,8 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
+import android.view.IPinnedStackController;
+import android.view.IPinnedStackListener;
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.View;
@@ -133,6 +135,7 @@
     private boolean mUseCarModeUi = false;
     private boolean mInCarMode = false;
     private boolean mDockedStackExists;
+    private boolean mImeVisible;
 
     private final SparseArray<ButtonDispatcher> mButtonDispatchers = new SparseArray<>();
     private final ContextualButtonGroup mContextualButtonGroup;
@@ -234,6 +237,45 @@
         }
     };
 
+    private final IPinnedStackListener.Stub mImeChangedListener = new IPinnedStackListener.Stub() {
+        @Override
+        public void onListenerRegistered(IPinnedStackController controller) {
+        }
+
+        @Override
+        public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
+            post(() -> {
+                // TODO remove this and do below when mNavigationIconHints changes
+                if (imeVisible) {
+                    getBackButton().setVisibility(VISIBLE);
+                    reloadNavIcons();
+                } else {
+                    getImeSwitchButton().setVisibility(GONE);
+                }
+                mImeVisible = imeVisible;
+                updateWindowTouchable();
+            });
+        }
+
+        @Override
+        public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) {
+        }
+
+        @Override
+        public void onMinimizedStateChanged(boolean isMinimized) {
+        }
+
+        @Override
+        public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
+                Rect animatingBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment,
+                int displayRotation) {
+        }
+
+        @Override
+        public void onActionsChanged(ParceledListSlice actions) {
+        }
+    };
+
     private BroadcastReceiver mOverlaysChangedReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -472,6 +514,11 @@
             return;
         }
 
+        if (QuickStepContract.isGesturalMode(getContext())) {
+            drawable.setRotation(degrees);
+            return;
+        }
+
         // Animate the back button's rotation to the new degrees and only in portrait move up the
         // back button to line up with the other buttons
         float targetY = !mOverviewProxyService.shouldShowSwipeUpUI() && !mIsVertical && useAltBack
@@ -574,8 +621,8 @@
         // Always disable recents when alternate car mode UI is active and for secondary displays.
         boolean disableRecent = isRecentsButtonDisabled();
 
-        boolean disableBack = QuickStepContract.isGesturalMode(getContext())
-                || (((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0) && !useAltBack);
+        boolean disableBack = !useAltBack && (QuickStepContract.isGesturalMode(getContext())
+                || ((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0));
 
         // When screen pinning, don't hide back and home when connected service or back and
         // recents buttons when disconnected from launcher service in screen pinning mode,
@@ -715,6 +762,11 @@
         setWindowFlag(WindowManager.LayoutParams.FLAG_SLIPPERY, slippery);
     }
 
+    public void updateWindowTouchable() {
+        boolean touchable = mImeVisible || !QuickStepContract.isGesturalMode(getContext());
+        setWindowFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, !touchable);
+    }
+
     private void setWindowFlag(int flags, boolean enable) {
         final ViewGroup navbarView = ((ViewGroup) getParent());
         if (navbarView == null) {
@@ -734,7 +786,7 @@
     }
 
     private void onOverlaysChanged() {
-        mNavigationInflaterView.onTuningChanged(NAV_BAR_VIEWS, null);
+        mNavigationInflaterView.setNavigationBarLayout(null);
 
         // Color adaption is tied with showing home handle, only avaliable if visible
         if (QuickStepContract.isGesturalMode(getContext())) {
@@ -1062,6 +1114,15 @@
         filter.addDataScheme("package");
         getContext().registerReceiver(mOverlaysChangedReceiver, filter);
         mEdgeBackGestureHandler.onNavBarAttached();
+
+        if (QuickStepContract.isGesturalMode(getContext())) {
+            try {
+                WindowManagerWrapper.getInstance().addPinnedStackListener(mImeChangedListener);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to register pinned stack listener", e);
+            }
+        }
+        updateWindowTouchable();
     }
 
     @Override
@@ -1078,6 +1139,8 @@
 
         getContext().unregisterReceiver(mOverlaysChangedReceiver);
         mEdgeBackGestureHandler.onNavBarDetached();
+
+        WindowManagerWrapper.getInstance().removePinnedStackListener(mImeChangedListener);
     }
 
     private void setUpSwipeUpOnboarding(boolean connectedToOverviewProxy) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java
index 6293b06..e3c081e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java
@@ -36,6 +36,7 @@
 import com.android.systemui.statusbar.policy.KeyButtonDrawable;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -173,6 +174,7 @@
     }
 
     @Test
+    @Ignore("b/112934365")
     public void testUpdateIconsDarkIntensity() throws Exception {
         final int unusedColor = 0;
         final Drawable d = mock(Drawable.class);
diff --git a/services/core/java/com/android/server/wm/NavigationBarExperiments.java b/services/core/java/com/android/server/wm/NavigationBarExperiments.java
index b74fb45..bb3ff5e 100644
--- a/services/core/java/com/android/server/wm/NavigationBarExperiments.java
+++ b/services/core/java/com/android/server/wm/NavigationBarExperiments.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
@@ -91,7 +90,7 @@
      * @param w the window that is being offset by experiment
      */
     public void offsetWindowFramesForNavBar(int navPosition, WindowState w) {
-        if (w.getAttrs().type != TYPE_INPUT_METHOD && w.getActivityType() != ACTIVITY_TYPE_HOME) {
+        if (w.getAttrs().type != TYPE_INPUT_METHOD) {
             return;
         }
 
@@ -102,6 +101,7 @@
                 int navHeight = getNavigationBarFrameHeight() - getNavigationBarHeight();
                 if (navHeight > 0) {
                     cf.bottom -= navHeight;
+                    windowFrames.mStableFrame.bottom -= navHeight;
                 }
                 break;
             case NAV_BAR_LEFT: