Merge "Support A11y contextual button" into sc-v2-dev
diff --git a/quickstep/res/drawable/ic_sysbar_accessibility_button.xml b/quickstep/res/drawable/ic_sysbar_accessibility_button.xml
new file mode 100644
index 0000000..e0d5406
--- /dev/null
+++ b/quickstep/res/drawable/ic_sysbar_accessibility_button.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2018 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="21dp"
+    android:height="21dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:pathData="M20.5,6c-2.61,0.7 -5.67,1 -8.5,1S6.11,6.7 3.5,6L3,8c1.86,0.5 4,0.83 6,1v13h2v-6h2v6h2V9c2,-0.17 4.14,-0.5 6,-1L20.5,6zM12,6c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2s-2,0.9 -2,2S10.9,6 12,6z"
+        android:fillColor="@android:color/white"
+        />
+</vector>
\ No newline at end of file
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonUIController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonUIController.java
index 1281b2e..dc292a1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonUIController.java
@@ -15,10 +15,16 @@
  */
 package com.android.launcher3.taskbar;
 
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y_LONG_CLICK;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING;
 
 import android.animation.ObjectAnimator;
 import android.annotation.DrawableRes;
@@ -58,14 +64,18 @@
     private static final int FLAG_SWITCHER_SUPPORTED = 1 << 0;
     private static final int FLAG_IME_VISIBLE = 1 << 1;
     private static final int FLAG_ROTATION_BUTTON_VISIBLE = 1 << 2;
+    private static final int FLAG_A11Y_VISIBLE = 1 << 3;
 
     private static final int MASK_IME_SWITCHER_VISIBLE = FLAG_SWITCHER_SUPPORTED | FLAG_IME_VISIBLE;
 
+    private View.OnLongClickListener mA11yLongClickListener;
     private final ArrayList<StatePropertyHolder> mPropertyHolders = new ArrayList<>();
     private final ArrayList<View> mAllButtons = new ArrayList<>();
     private int mState;
 
     private final TaskbarActivityContext mContext;
+    private View a11yButton;
+    private int mSysuiStateFlags;
 
     public NavbarButtonUIController(TaskbarActivityContext context) {
         mContext = context;
@@ -81,6 +91,11 @@
         FrameLayout buttonController = dragLayer.findViewById(R.id.navbuttons_view);
         buttonController.getLayoutParams().height = mContext.getDeviceProfile().taskbarSize;
 
+        mA11yLongClickListener = view -> {
+            navButtonController.onButtonClick(BUTTON_A11Y_LONG_CLICK);
+            return true;
+        };
+
         if (mContext.canShowNavButtons()) {
             ViewGroup startContainer = buttonController.findViewById(R.id.start_nav_buttons);
             ViewGroup endContainer = buttonController.findViewById(R.id.end_nav_buttons);
@@ -132,18 +147,34 @@
                 endContainer, navButtonController);
         mPropertyHolders.add(new StatePropertyHolder(imeSwitcherButton,
                 flags -> ((flags & MASK_IME_SWITCHER_VISIBLE) == MASK_IME_SWITCHER_VISIBLE)
-                        && ((flags & FLAG_ROTATION_BUTTON_VISIBLE) == 0)));
+                        && ((flags & FLAG_ROTATION_BUTTON_VISIBLE) == 0)
+                        && ((flags & FLAG_A11Y_VISIBLE) == 0)));
+
+        // A11y button
+        a11yButton = addButton(R.drawable.ic_sysbar_accessibility_button, BUTTON_A11Y,
+                endContainer, navButtonController);
+        mPropertyHolders.add(new StatePropertyHolder(a11yButton,
+                flags -> (flags & FLAG_A11Y_VISIBLE) != 0
+                        && (flags & FLAG_ROTATION_BUTTON_VISIBLE) == 0));
+        a11yButton.setOnLongClickListener(mA11yLongClickListener);
     }
 
-    /**
-     * Should be called when the IME visibility changes, so we can hide/show Taskbar accordingly.
-     */
-    public void setImeIsVisible(boolean isImeVisible) {
-        if (isImeVisible) {
-            mState |= FLAG_IME_VISIBLE;
-        } else {
-            mState &= ~FLAG_IME_VISIBLE;
+    public void updateStateForSysuiFlags(int systemUiStateFlags, boolean forceUpdate) {
+        boolean isImeVisible = (systemUiStateFlags & SYSUI_STATE_IME_SHOWING) != 0;
+        boolean isImeSwitcherShowing = (systemUiStateFlags & SYSUI_STATE_IME_SWITCHER_SHOWING) != 0;
+        boolean a11yVisible = (systemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
+        boolean a11yLongClickable =
+                (systemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
+
+        if (!forceUpdate && systemUiStateFlags == mSysuiStateFlags) {
+            return;
         }
+        mSysuiStateFlags = systemUiStateFlags;
+
+        updateStateForFlag(FLAG_IME_VISIBLE, isImeVisible);
+        updateStateForFlag(FLAG_SWITCHER_SUPPORTED, isImeSwitcherShowing);
+        updateStateForFlag(FLAG_A11Y_VISIBLE, a11yVisible);
+        a11yButton.setLongClickable(a11yLongClickable);
         applyState();
     }
 
@@ -169,15 +200,14 @@
     }
 
     /**
-     * Sets if ime switcher is visible or not when ime is visible
+     * Does not call {@link #applyState()}. Don't forget to!
      */
-    public void setImeSwitcherVisible(boolean imeSwitcherVisible) {
-        if (imeSwitcherVisible) {
-            mState |= FLAG_SWITCHER_SUPPORTED;
+    private void updateStateForFlag(int flag, boolean enabled) {
+        if (enabled) {
+            mState |= flag;
         } else {
-            mState &= ~FLAG_SWITCHER_SUPPORTED;
+            mState &= ~flag;
         }
-        applyState();
     }
 
     private void applyState() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 5f7dce5..a25eb38 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -29,7 +29,6 @@
 import android.content.pm.LauncherApps;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
-import android.inputmethodservice.InputMethodService;
 import android.os.Process;
 import android.os.SystemProperties;
 import android.util.Log;
@@ -51,7 +50,6 @@
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
 import com.android.launcher3.taskbar.contextual.RotationButtonController;
 import com.android.launcher3.touch.ItemClickHandler;
 import com.android.launcher3.util.MultiValueAlpha;
@@ -231,30 +229,12 @@
         mWindowManager.removeViewImmediate(mDragLayer);
     }
 
-    void onNavigationButtonClick(@TaskbarButton int buttonType) {
-        mNavButtonController.onButtonClick(buttonType);
-    }
-
-    /**
-     * Should be called when the IME visibility changes, so we can hide/show Taskbar accordingly.
-     */
-    public void setImeIsVisible(boolean isImeVisible) {
-        mIconController.setImeIsVisible(isImeVisible);
-        mNavbarButtonUIController.setImeIsVisible(isImeVisible);
-    }
-
-    /**
-     * When in 3 button nav, the above doesn't get called since we prevent sysui nav bar from
-     * instantiating at all, which is what's responsible for sending sysui state flags over.
-     *
-     * @param vis IME visibility flag
-     */
-    public void updateImeStatus(int displayId, int vis, boolean showImeSwitcher) {
-        if (displayId != getDisplayId() || !canShowNavButtons()) {
+    public void updateSysuiStateFlags(int systemUiStateFlags, boolean forceUpdate) {
+        if (!canShowNavButtons()) {
             return;
         }
-        mNavbarButtonUIController.setImeSwitcherVisible(showImeSwitcher);
-        setImeIsVisible((vis & InputMethodService.IME_VISIBLE) != 0);
+        mNavbarButtonUIController.updateStateForSysuiFlags(systemUiStateFlags, forceUpdate);
+        mIconController.setImeIsVisible(mNavbarButtonUIController.isImeVisible());
     }
 
     public void onRotationProposal(int rotation, boolean isValid) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 36bccee..3563d09 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -21,11 +21,9 @@
 import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
 import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
 import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUNDS;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
 
 import android.content.Context;
 import android.hardware.display.DisplayManager;
-import android.inputmethodservice.InputMethodService;
 import android.view.Display;
 
 import androidx.annotation.Nullable;
@@ -53,6 +51,11 @@
 
     private TaskbarActivityContext mTaskbarActivityContext;
     private BaseQuickstepLauncher mLauncher;
+    /**
+     * Cache a copy here so we can initialize state whenever taskbar is recreated, since
+     * this class does not get re-initialized w/ new taskbars.
+     */
+    private int mSysuiStateFlags;
 
     private static final int CHANGE_FLAGS =
             CHANGE_ACTIVE_SCREEN | CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS;
@@ -130,6 +133,7 @@
             mTaskbarActivityContext.setUIController(
                     new LauncherTaskbarUIController(mLauncher, mTaskbarActivityContext));
         }
+        onSysuiFlagsChangedInternal(mSysuiStateFlags, true /* forceUpdate */);
     }
 
     /**
@@ -137,24 +141,13 @@
      * @param systemUiStateFlags The latest SystemUiStateFlags
      */
     public void onSystemUiFlagsChanged(int systemUiStateFlags) {
-        boolean isImeVisible = (systemUiStateFlags & SYSUI_STATE_IME_SHOWING) != 0;
-        if (mTaskbarActivityContext != null) {
-            mTaskbarActivityContext.setImeIsVisible(isImeVisible);
-        }
+        onSysuiFlagsChangedInternal(systemUiStateFlags, false /* forceUpdate */);
     }
 
-    /**
-     * When in 3 button nav, the above doesn't get called since we prevent sysui nav bar from
-     * instantiating at all, which is what's responsible for sending sysui state flags over.
-     *
-     * @param vis IME visibility flag
-     * @param backDisposition Used to determine back button behavior for software keyboard
-     *                        See BACK_DISPOSITION_* constants in {@link InputMethodService}
-     */
-    public void updateImeStatus(int displayId, int vis, int backDisposition,
-            boolean showImeSwitcher) {
+    private void onSysuiFlagsChangedInternal(int systemUiStateFlags, boolean forceUpdate) {
+        mSysuiStateFlags = systemUiStateFlags;
         if (mTaskbarActivityContext != null) {
-            mTaskbarActivityContext.updateImeStatus(displayId, vis, showImeSwitcher);
+            mTaskbarActivityContext.updateSysuiStateFlags(systemUiStateFlags, forceUpdate);
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index 3b5afad..002d42d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -44,7 +44,9 @@
             BUTTON_BACK,
             BUTTON_HOME,
             BUTTON_RECENTS,
-            BUTTON_IME_SWITCH
+            BUTTON_IME_SWITCH,
+            BUTTON_A11Y,
+            BUTTON_A11Y_LONG_CLICK
     })
 
     public @interface TaskbarButton {}
@@ -53,6 +55,8 @@
     static final int BUTTON_HOME = BUTTON_BACK << 1;
     static final int BUTTON_RECENTS = BUTTON_HOME << 1;
     static final int BUTTON_IME_SWITCH = BUTTON_RECENTS << 1;
+    static final int BUTTON_A11Y = BUTTON_IME_SWITCH << 1;
+    static final int BUTTON_A11Y_LONG_CLICK = BUTTON_A11Y << 1;
 
     private final TouchInteractionService mService;
 
@@ -74,6 +78,12 @@
             case BUTTON_IME_SWITCH:
                 showIMESwitcher();
                 break;
+            case BUTTON_A11Y:
+                notifyImeClick(false /* longClick */);
+                break;
+            case BUTTON_A11Y_LONG_CLICK:
+                notifyImeClick(true /* longClick */);
+                break;
         }
     }
 
@@ -97,4 +107,13 @@
                 .showInputMethodPickerFromSystem(true /* showAuxiliarySubtypes */,
                         DEFAULT_DISPLAY);
     }
+
+    private void notifyImeClick(boolean longClick) {
+        SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.getNoCreate();
+        if (longClick) {
+            systemUiProxy.notifyAccessibilityButtonLongClicked();
+        } else {
+            systemUiProxy.notifyAccessibilityButtonClicked(mService.getDisplayId());
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index afafce7..a3136c7 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -267,13 +267,6 @@
         }
 
         @Override
-        public void onImeWindowStatusChanged(int displayId, IBinder token, int vis,
-                int backDisposition, boolean showImeSwitcher) {
-            executeForTaskbarManager(() -> mTaskbarManager
-                    .updateImeStatus(displayId, vis, backDisposition, showImeSwitcher));
-        }
-
-        @Override
         public void onRotationProposal(int rotation, boolean isValid) {
             executeForTaskbarManager(() -> mTaskbarManager.onRotationProposal(rotation, isValid));
         }