From d821b27254aa465c86a540b0a9c9510adf230635 Mon Sep 17 00:00:00 2001 From: Peter_Liang Date: Wed, 2 Mar 2022 20:17:57 +0800 Subject: [PATCH] Fix that cut-over OTA to Android T disabled magnification via nav-bar accessibility shortcut. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: Didn’t initial the correct accessibility state when creating the navigation bar view. Solution: Add updateA11yState() into the init() and onAccessibilityServicesStateChanged(AccessibilityManager) Bug: 219732138 Test: atest NavBarHelperTest Change-Id: Idf951088cbbaacf259026aace4e7090fb9903c0e --- .../systemui/navigationbar/NavBarHelper.java | 29 ++++++--- .../navigationbar/NavBarHelperTest.java | 60 +++++++++++++++++++ 2 files changed, 82 insertions(+), 7 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java index a1a319814269a..df820a722e288 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java @@ -33,6 +33,7 @@ import android.os.Handler; import android.os.Looper; import android.os.UserHandle; import android.provider.Settings; +import android.provider.Settings.Secure; import android.view.View; import android.view.WindowInsets; import android.view.accessibility.AccessibilityManager; @@ -72,6 +73,7 @@ import dagger.Lazy; */ @SysUISingleton public final class NavBarHelper implements + AccessibilityManager.AccessibilityServicesStateChangeListener, AccessibilityButtonModeObserver.ModeChangedListener, AccessibilityButtonTargetsObserver.TargetsChangedListener, OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener, @@ -123,8 +125,7 @@ public final class NavBarHelper implements mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; mUserTracker = userTracker; mSystemActions = systemActions; - accessibilityManager.addAccessibilityServicesStateChangeListener( - accessibilityManager1 -> NavBarHelper.this.dispatchA11yEventUpdate()); + accessibilityManager.addAccessibilityServicesStateChangeListener(this); mAccessibilityButtonModeObserver = accessibilityButtonModeObserver; mAccessibilityButtonTargetsObserver = accessibilityButtonTargetsObserver; @@ -146,6 +147,7 @@ public final class NavBarHelper implements Settings.Secure.getUriFor(Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED), false, mAssistContentObserver, UserHandle.USER_ALL); updateAssistantAvailability(); + updateA11yState(); } public void destroy() { @@ -177,6 +179,12 @@ public final class NavBarHelper implements } } + @Override + public void onAccessibilityServicesStateChanged(AccessibilityManager manager) { + dispatchA11yEventUpdate(); + updateA11yState(); + } + @Override public void onAccessibilityButtonModeChanged(int mode) { updateA11yState(); @@ -190,7 +198,9 @@ public final class NavBarHelper implements } /** - * Updates the current accessibility button state. + * Updates the current accessibility button state. The accessibility button state is only + * used for {@link Secure#ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR} and + * {@link Secure#ACCESSIBILITY_BUTTON_MODE_GESTURE}, otherwise it is reset to 0. */ private void updateA11yState() { final int prevState = mA11yButtonState; @@ -213,6 +223,9 @@ public final class NavBarHelper implements final int requestingServices = a11yButtonTargets.size(); clickable = requestingServices >= 1; + + // `longClickable` is used to determine whether to pop up the accessibility chooser + // dialog or not, and it’s also only for multiple services. longClickable = requestingServices >= 2; mA11yButtonState = (clickable ? SYSUI_STATE_A11Y_BUTTON_CLICKABLE : 0) | (longClickable ? SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE : 0); @@ -237,11 +250,13 @@ public final class NavBarHelper implements } /** - * See {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_CLICKABLE} and - * {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE} + * Gets the accessibility button state based on the {@link Secure#ACCESSIBILITY_BUTTON_MODE}. * - * @return the a11y button clickable and long_clickable states, or 0 if there is no - * a11y button in the navbar + * @return the accessibility button state: + * 0 = disable state + * 16 = {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_CLICKABLE} + * 48 = the combination of {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_CLICKABLE} and + * {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE} */ public int getA11yButtonState() { return mA11yButtonState; diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java index 634d9e4642b37..edcf4791e6b18 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java @@ -16,8 +16,18 @@ package com.android.systemui.navigationbar; +import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; +import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; + +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.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -45,10 +55,15 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import dagger.Lazy; +/** + * Tests for {@link NavBarHelper}. + */ @RunWith(AndroidJUnit4.class) @SmallTest public class NavBarHelperTest extends SysuiTestCase { @@ -77,7 +92,11 @@ public class NavBarHelperTest extends SysuiTestCase { DumpManager mDumpManager; @Mock NavBarHelper.NavbarTaskbarStateUpdater mNavbarTaskbarStateUpdater; + private AccessibilityManager.AccessibilityServicesStateChangeListener + mAccessibilityServicesStateChangeListener; + private static final int ACCESSIBILITY_BUTTON_CLICKABLE_STATE = + SYSUI_STATE_A11Y_BUTTON_CLICKABLE | SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE; private NavBarHelper mNavBarHelper; @Before @@ -87,6 +106,9 @@ public class NavBarHelperTest extends SysuiTestCase { when(mAssistManager.getAssistInfoForUser(anyInt())).thenReturn(mAssistantComponent); when(mUserTracker.getUserId()).thenReturn(1); + doAnswer((invocation) -> mAccessibilityServicesStateChangeListener = + invocation.getArgument(0)).when( + mAccessibilityManager).addAccessibilityServicesStateChangeListener(any()); mNavBarHelper = new NavBarHelper(mContext, mAccessibilityManager, mAccessibilityButtonModeObserver, mAccessibilityButtonTargetObserver, mSystemActions, mOverviewProxyService, mAssistManagerLazy, @@ -183,4 +205,42 @@ public class NavBarHelperTest extends SysuiTestCase { verify(mNavbarTaskbarStateUpdater, times(1)) .updateAssistantAvailable(anyBoolean()); } + + @Test + public void initNavBarHelper_buttonModeNavBar_a11yButtonClickableState() { + when(mAccessibilityManager.getAccessibilityShortcutTargets( + AccessibilityManager.ACCESSIBILITY_BUTTON)).thenReturn(createFakeShortcutTargets()); + + mNavBarHelper.init(); + + assertThat(mNavBarHelper.getA11yButtonState()).isEqualTo( + ACCESSIBILITY_BUTTON_CLICKABLE_STATE); + } + + @Test + public void initAccessibilityStateWithFloatingMenuModeAndTargets_disableClickableState() { + when(mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()).thenReturn( + ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU); + mNavBarHelper.init(); + + assertThat(mNavBarHelper.getA11yButtonState()).isEqualTo(/* disable_clickable_state */ 0); + } + + @Test + public void onA11yServicesStateChangedWithMultipleServices_a11yButtonClickableState() { + when(mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()).thenReturn( + ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR); + + when(mAccessibilityManager.getAccessibilityShortcutTargets( + AccessibilityManager.ACCESSIBILITY_BUTTON)).thenReturn(createFakeShortcutTargets()); + mAccessibilityServicesStateChangeListener.onAccessibilityServicesStateChanged( + mAccessibilityManager); + + assertThat(mNavBarHelper.getA11yButtonState()).isEqualTo( + ACCESSIBILITY_BUTTON_CLICKABLE_STATE); + } + + private List createFakeShortcutTargets() { + return new ArrayList<>(List.of("a", "b", "c", "d")); + } }