From e568781206b9a781ac3d01a7e4e5519bc24af011 Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Mon, 7 Jun 2021 16:42:43 -0700 Subject: [PATCH] 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 --- .../ic_sysbar_accessibility_button.xml | 26 ++++++++ .../taskbar/NavbarButtonUIController.java | 60 ++++++++++++++----- .../taskbar/TaskbarActivityContext.java | 28 ++------- .../launcher3/taskbar/TaskbarManager.java | 27 ++++----- .../taskbar/TaskbarNavButtonController.java | 21 ++++++- .../quickstep/TouchInteractionService.java | 7 --- 6 files changed, 105 insertions(+), 64 deletions(-) create mode 100644 quickstep/res/drawable/ic_sysbar_accessibility_button.xml 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 0000000000..e0d5406810 --- /dev/null +++ b/quickstep/res/drawable/ic_sysbar_accessibility_button.xml @@ -0,0 +1,26 @@ + + + + + \ 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 1281b2e38f..dc292a1816 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 @@ public class NavbarButtonUIController { 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 mPropertyHolders = new ArrayList<>(); private final ArrayList 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 @@ public class NavbarButtonUIController { 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 @@ public class NavbarButtonUIController { 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 @@ public class NavbarButtonUIController { } /** - * 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 5f7dce5fac..a25eb38d99 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.Intent; 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.Folder; 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 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ 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 36bccee464..3563d09573 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 android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; 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 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen 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 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen mTaskbarActivityContext.setUIController( new LauncherTaskbarUIController(mLauncher, mTaskbarActivityContext)); } + onSysuiFlagsChangedInternal(mSysuiStateFlags, true /* forceUpdate */); } /** @@ -137,24 +141,13 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen * @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 3b5afad691..002d42da3b 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java @@ -44,7 +44,9 @@ public class TaskbarNavButtonController { 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 @@ public class TaskbarNavButtonController { 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 @@ public class TaskbarNavButtonController { 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 @@ public class TaskbarNavButtonController { .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 afafce7382..a3136c7dd8 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -266,13 +266,6 @@ public class TouchInteractionService extends Service implements PluginListener SplitScreenBounds.INSTANCE.setSecondaryWindowBounds(wb)); } - @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));