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 112e9cae0a214..0ab14c0a08a79 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java @@ -20,11 +20,12 @@ 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; import com.android.internal.annotations.VisibleForTesting; +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.accessibility.AccessibilityButtonModeObserver; import com.android.systemui.accessibility.AccessibilityButtonModeObserver.AccessibilityButtonMode; import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver; @@ -37,41 +38,52 @@ import javax.inject.Inject; @SysUISingleton public class AccessibilityFloatingMenuController implements AccessibilityButtonModeObserver.ModeChangedListener, - AccessibilityButtonTargetsObserver.TargetsChangedListener, - AccessibilityManager.AccessibilityStateChangeListener { + AccessibilityButtonTargetsObserver.TargetsChangedListener { private final Context mContext; - private final AccessibilityManager mAccessibilityManager; private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver; private final AccessibilityButtonTargetsObserver mAccessibilityButtonTargetsObserver; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; @VisibleForTesting IAccessibilityFloatingMenu mFloatingMenu; private int mBtnMode; private String mBtnTargets; + private boolean mIsKeyguardVisible; + private boolean mIsAccessibilityManagerServiceReady; + + @VisibleForTesting + final KeyguardUpdateMonitorCallback mKeyguardCallback = new KeyguardUpdateMonitorCallback() { + // Accessibility floating menu needs to retrieve information from + // AccessibilityManagerService, and it would be ready before onUserUnlocked(). + @Override + public void onUserUnlocked() { + mIsAccessibilityManagerServiceReady = true; + handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets); + } + + // Keyguard state would be changed before AccessibilityManagerService is ready to retrieve, + // need to wait until receive onUserUnlocked(). + @Override + public void onKeyguardVisibilityChanged(boolean showing) { + mIsKeyguardVisible = showing; + if (mIsAccessibilityManagerServiceReady) { + handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets); + } + } + }; @Inject public AccessibilityFloatingMenuController(Context context, AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver, - AccessibilityButtonModeObserver accessibilityButtonModeObserver) { + AccessibilityButtonModeObserver accessibilityButtonModeObserver, + KeyguardUpdateMonitor keyguardUpdateMonitor) { mContext = context; mAccessibilityButtonTargetsObserver = accessibilityButtonTargetsObserver; mAccessibilityButtonModeObserver = accessibilityButtonModeObserver; - mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class); + mKeyguardUpdateMonitor = keyguardUpdateMonitor; - mAccessibilityButtonModeObserver.addListener(this); - mAccessibilityButtonTargetsObserver.addListener(this); - mBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode(); - mBtnTargets = mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets(); - - // 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); - } + init(); } /** @@ -82,7 +94,7 @@ public class AccessibilityFloatingMenuController implements @Override public void onAccessibilityButtonModeChanged(@AccessibilityButtonMode int mode) { mBtnMode = mode; - handleFloatingMenuVisibility(mBtnMode, mBtnTargets); + handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets); } /** @@ -94,27 +106,39 @@ public class AccessibilityFloatingMenuController implements @Override public void onAccessibilityButtonTargetsChanged(String targets) { mBtnTargets = targets; - handleFloatingMenuVisibility(mBtnMode, mBtnTargets); + handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets); + } + + private void init() { + mIsKeyguardVisible = false; + mIsAccessibilityManagerServiceReady = false; + mBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode(); + mBtnTargets = mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets(); + registerContentObservers(); + } + + private void registerContentObservers() { + mAccessibilityButtonModeObserver.addListener(this); + mAccessibilityButtonTargetsObserver.addListener(this); + mKeyguardUpdateMonitor.registerCallback(mKeyguardCallback); } /** - * 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. + * Handles the accessibility floating menu visibility with the given values. * - * @param enabled Whether accessibility is enabled. + * @param keyguardVisible the keyguard visibility status. Not show the + * {@link AccessibilityFloatingMenu} when keyguard appears. + * @param mode accessibility button mode {@link AccessibilityButtonMode} + * @param targets accessibility button list; it should comes from + * {@link android.provider.Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS}. */ - @Override - public void onAccessibilityStateChanged(boolean enabled) { - if (enabled) { - handleFloatingMenuVisibility(mBtnMode, mBtnTargets); + private void handleFloatingMenuVisibility(boolean keyguardVisible, + @AccessibilityButtonMode int mode, String targets) { + if (keyguardVisible) { + destroyFloatingMenu(); + return; } - mAccessibilityManager.removeAccessibilityStateChangeListener(this); - } - - private void handleFloatingMenuVisibility(@AccessibilityButtonMode int mode, String targets) { if (shouldShowFloatingMenu(mode, targets)) { showFloatingMenu(); } else { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java index 187caf9c2b2e1..746621dfda274 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java @@ -41,6 +41,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; import com.android.internal.util.NotificationMessagingUtil; import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.ViewMediatorCallback; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.systemui.Prefs; @@ -263,9 +264,10 @@ public class DependencyProvider { @SysUISingleton public AccessibilityFloatingMenuController provideAccessibilityFloatingMenuController( Context context, AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver, - AccessibilityButtonModeObserver accessibilityButtonModeObserver) { + AccessibilityButtonModeObserver accessibilityButtonModeObserver, + KeyguardUpdateMonitor keyguardUpdateMonitor) { return new AccessibilityFloatingMenuController(context, accessibilityButtonTargetsObserver, - accessibilityButtonModeObserver); + accessibilityButtonModeObserver, keyguardUpdateMonitor); } /** */ 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 a83f0382ba7bc..ac9aa985062d1 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,15 +24,15 @@ 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; +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.accessibility.AccessibilityButtonModeObserver; @@ -41,7 +41,8 @@ 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.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -56,11 +57,13 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { @Rule public MockitoRule mockito = MockitoJUnit.rule(); + private KeyguardUpdateMonitor mKeyguardUpdateMonitor; private AccessibilityFloatingMenuController mController; private AccessibilityButtonTargetsObserver mTargetsObserver; private AccessibilityButtonModeObserver mModeObserver; - @Mock - private AccessibilityManager mMockA11yManager; + @Captor + private ArgumentCaptor mKeyguardCallbackCaptor; + private KeyguardUpdateMonitorCallback mKeyguardCallback; @Test public void initController_registerListeners() { @@ -70,37 +73,56 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { any(AccessibilityButtonTargetsObserver.TargetsChangedListener.class)); verify(mModeObserver).addListener( any(AccessibilityButtonModeObserver.ModeChangedListener.class)); - verify(mMockA11yManager).addAccessibilityStateChangeListener(any( - AccessibilityManager.AccessibilityStateChangeListener.class)); + verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.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); - + public void onUserUnlocked_keyguardNotShow_showWidget() { + enableAccessibilityFloatingMenuConfig(); mController = setUpController(); + captureKeyguardUpdateMonitorCallback(); + mKeyguardCallback.onKeyguardVisibilityChanged(false); + + mKeyguardCallback.onUserUnlocked(); 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); - + public void onUserUnlocked_keyguardShowing_destroyWidget() { + enableAccessibilityFloatingMenuConfig(); mController = setUpController(); - mController.onAccessibilityStateChanged(true); + captureKeyguardUpdateMonitorCallback(); + mKeyguardCallback.onKeyguardVisibilityChanged(true); + + mKeyguardCallback.onUserUnlocked(); + + assertThat(mController.mFloatingMenu).isNull(); + } + + @Test + public void onKeyguardVisibilityChanged_showing_destroyWidget() { + enableAccessibilityFloatingMenuConfig(); + mController = setUpController(); + mController.mFloatingMenu = new AccessibilityFloatingMenu(mContext); + captureKeyguardUpdateMonitorCallback(); + mKeyguardCallback.onUserUnlocked(); + + mKeyguardCallback.onKeyguardVisibilityChanged(true); + + assertThat(mController.mFloatingMenu).isNull(); + } + + @Test + public void onKeyguardVisibilityChanged_notShow_showWidget() { + enableAccessibilityFloatingMenuConfig(); + mController = setUpController(); + captureKeyguardUpdateMonitorCallback(); + mKeyguardCallback.onUserUnlocked(); + + mKeyguardCallback.onKeyguardVisibilityChanged(false); assertThat(mController.mFloatingMenu).isNotNull(); - verify(mMockA11yManager).removeAccessibilityStateChangeListener(mController); } @Test @@ -126,7 +148,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { } @Test - public void onAccessibilityButtonModeChanged_navBarModeAndHasButtonTargets_showWidget() { + public void onAccessibilityButtonModeChanged_navBarModeAndHasButtonTargets_destroyWidget() { Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS); mController = setUpController(); @@ -170,7 +192,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { } @Test - public void onAccessibilityButtonTargetsChanged_navBarModeAndHasButtonTargets_showWidget() { + public void onAccessibilityButtonTargetsChanged_navBarModeAndHasButtonTargets_destroyWidget() { Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR); @@ -182,7 +204,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { } @Test - public void onAccessibilityButtonTargetsChanged_buttonModeAndNoButtonTargets_destroyWidget() { + public void onAccessibilityButtonTargetsChanged_navBarModeAndNoButtonTargets_destroyWidget() { Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR); @@ -196,9 +218,21 @@ 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); + mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); return new AccessibilityFloatingMenuController(mContext, mTargetsObserver, - mModeObserver); + mModeObserver, mKeyguardUpdateMonitor); + } + + private void enableAccessibilityFloatingMenuConfig() { + 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); + } + + private void captureKeyguardUpdateMonitorCallback() { + verify(mKeyguardUpdateMonitor).registerCallback(mKeyguardCallbackCaptor.capture()); + mKeyguardCallback = mKeyguardCallbackCaptor.getValue(); } }