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));