diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java index fddbee393e4fb..112e9cae0a214 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java @@ -20,6 +20,7 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATIN import android.content.Context; import android.text.TextUtils; +import android.view.accessibility.AccessibilityManager; import androidx.annotation.MainThread; @@ -36,9 +37,11 @@ import javax.inject.Inject; @SysUISingleton public class AccessibilityFloatingMenuController implements AccessibilityButtonModeObserver.ModeChangedListener, - AccessibilityButtonTargetsObserver.TargetsChangedListener { + AccessibilityButtonTargetsObserver.TargetsChangedListener, + AccessibilityManager.AccessibilityStateChangeListener { private final Context mContext; + private final AccessibilityManager mAccessibilityManager; private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver; private final AccessibilityButtonTargetsObserver mAccessibilityButtonTargetsObserver; @@ -54,13 +57,21 @@ public class AccessibilityFloatingMenuController implements mContext = context; mAccessibilityButtonTargetsObserver = accessibilityButtonTargetsObserver; mAccessibilityButtonModeObserver = accessibilityButtonModeObserver; + mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class); mAccessibilityButtonModeObserver.addListener(this); mAccessibilityButtonTargetsObserver.addListener(this); mBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode(); mBtnTargets = mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets(); - handleFloatingMenuVisibility(mBtnMode, mBtnTargets); + // Accessibility floating menu widget needs accessibility service to work, but system + // accessibility might be unavailable during the phone get booted, hence it needs to wait + // for accessibility manager callback to work. + mAccessibilityManager.addAccessibilityStateChangeListener(this); + if (mAccessibilityManager.isEnabled()) { + handleFloatingMenuVisibility(mBtnMode, mBtnTargets); + mAccessibilityManager.removeAccessibilityStateChangeListener(this); + } } /** @@ -86,6 +97,23 @@ public class AccessibilityFloatingMenuController implements handleFloatingMenuVisibility(mBtnMode, mBtnTargets); } + /** + * Handles visibility of the accessibility floating menu when system accessibility state + * changes. + * If system accessibility become available onAccessibilityStateChanged(true), then we don't + * need to listen to this listener anymore. + * + * @param enabled Whether accessibility is enabled. + */ + @Override + public void onAccessibilityStateChanged(boolean enabled) { + if (enabled) { + handleFloatingMenuVisibility(mBtnMode, mBtnTargets); + } + + mAccessibilityManager.removeAccessibilityStateChangeListener(this); + } + private void handleFloatingMenuVisibility(@AccessibilityButtonMode int mode, String targets) { if (shouldShowFloatingMenu(mode, targets)) { showFloatingMenu(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java index 0663f46a00e98..a83f0382ba7bc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java @@ -24,10 +24,12 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.provider.Settings; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.view.accessibility.AccessibilityManager; import androidx.test.filters.SmallTest; @@ -36,8 +38,12 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.accessibility.AccessibilityButtonModeObserver; import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; /** Test for {@link AccessibilityFloatingMenuController}. */ @RunWith(AndroidTestingRunner.class) @@ -47,9 +53,14 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { private static final String TEST_A11Y_BTN_TARGETS = "Magnification"; + @Rule + public MockitoRule mockito = MockitoJUnit.rule(); + private AccessibilityFloatingMenuController mController; private AccessibilityButtonTargetsObserver mTargetsObserver; private AccessibilityButtonModeObserver mModeObserver; + @Mock + private AccessibilityManager mMockA11yManager; @Test public void initController_registerListeners() { @@ -59,6 +70,37 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { any(AccessibilityButtonTargetsObserver.TargetsChangedListener.class)); verify(mModeObserver).addListener( any(AccessibilityButtonModeObserver.ModeChangedListener.class)); + verify(mMockA11yManager).addAccessibilityStateChangeListener(any( + AccessibilityManager.AccessibilityStateChangeListener.class)); + } + + @Test + public void initController_accessibilityManagerEnabled_showWidget() { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU); + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS); + when(mMockA11yManager.isEnabled()).thenReturn(true); + + mController = setUpController(); + + assertThat(mController.mFloatingMenu).isNotNull(); + verify(mMockA11yManager).removeAccessibilityStateChangeListener(mController); + } + + @Test + public void initController_accessibilityManagerDisabledThenCallbackToEnabled_showWidget() { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU); + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS); + when(mMockA11yManager.isEnabled()).thenReturn(false); + + mController = setUpController(); + mController.onAccessibilityStateChanged(true); + + assertThat(mController.mFloatingMenu).isNotNull(); + verify(mMockA11yManager).removeAccessibilityStateChangeListener(mController); } @Test @@ -154,7 +196,9 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { private AccessibilityFloatingMenuController setUpController() { mTargetsObserver = spy(Dependency.get(AccessibilityButtonTargetsObserver.class)); mModeObserver = spy(Dependency.get(AccessibilityButtonModeObserver.class)); + mContext.addMockSystemService(AccessibilityManager.class, mMockA11yManager); - return new AccessibilityFloatingMenuController(mContext, mTargetsObserver, mModeObserver); + return new AccessibilityFloatingMenuController(mContext, mTargetsObserver, + mModeObserver); } }