Support A11y contextual button

Also migrate to only using sysui state flags
for ime/switcher visibility instead of 2 separate
methods.

Bug: 180046394
Test: Tested w/ 1 a11y service, then 2 services for
long click. Tested with IME switcher enabled and then
also suggested rotation button.
A11y takes precedence over IME switcher, but rotation button
takes precedence over a11y as is in phone mode today.

Change-Id: I9289165c8ca98d7ee432bd7145122d6a519600f6
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));
         }