diff options
13 files changed, 707 insertions, 67 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index ae4c8e5a3327..06b486ec43d0 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -34,6 +34,9 @@ import com.android.keyguard.KeyguardSecurityModel; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.clock.ClockManager; import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.systemui.accessibility.AccessibilityButtonModeObserver; +import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver; +import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController; import com.android.systemui.appops.AppOpsController; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; @@ -284,6 +287,8 @@ public class Dependency { @Inject Lazy<IWindowManager> mIWindowManager; @Inject Lazy<OverviewProxyService> mOverviewProxyService; @Inject Lazy<NavigationModeController> mNavBarModeController; + @Inject Lazy<AccessibilityButtonModeObserver> mAccessibilityButtonModeObserver; + @Inject Lazy<AccessibilityButtonTargetsObserver> mAccessibilityButtonListController; @Inject Lazy<EnhancedEstimates> mEnhancedEstimates; @Inject Lazy<VibratorHelper> mVibratorHelper; @Inject Lazy<IStatusBarService> mIStatusBarService; @@ -294,6 +299,7 @@ public class Dependency { @Inject Lazy<NotificationRemoteInputManager.Callback> mNotificationRemoteInputManagerCallback; @Inject Lazy<AppOpsController> mAppOpsController; @Inject Lazy<NavigationBarController> mNavigationBarController; + @Inject Lazy<AccessibilityFloatingMenuController> mAccessibilityFloatingMenuController; @Inject Lazy<StatusBarStateController> mStatusBarStateController; @Inject Lazy<NotificationLockscreenUserManager> mNotificationLockscreenUserManager; @Inject Lazy<NotificationGroupAlertTransferHelper> mNotificationGroupAlertTransferHelper; @@ -470,6 +476,11 @@ public class Dependency { mProviders.put(NavigationModeController.class, mNavBarModeController::get); + mProviders.put(AccessibilityButtonModeObserver.class, + mAccessibilityButtonModeObserver::get); + mProviders.put(AccessibilityButtonTargetsObserver.class, + mAccessibilityButtonListController::get); + mProviders.put(EnhancedEstimates.class, mEnhancedEstimates::get); mProviders.put(VibratorHelper.class, mVibratorHelper::get); @@ -489,6 +500,9 @@ public class Dependency { mProviders.put(NavigationBarController.class, mNavigationBarController::get); + mProviders.put(AccessibilityFloatingMenuController.class, + mAccessibilityFloatingMenuController::get); + mProviders.put(StatusBarStateController.class, mStatusBarStateController::get); mProviders.put(NotificationLockscreenUserManager.class, mNotificationLockscreenUserManager::get); diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonModeObserver.java b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonModeObserver.java index 39d8dbb3beec..9bedb1ea7563 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonModeObserver.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonModeObserver.java @@ -21,23 +21,14 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGAT import android.annotation.IntDef; import android.annotation.MainThread; -import android.content.ContentResolver; import android.content.Context; -import android.database.ContentObserver; -import android.os.Handler; -import android.os.Looper; import android.provider.Settings; +import android.util.Log; -import androidx.annotation.NonNull; - -import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.dagger.SysUISingleton; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; import javax.inject.Inject; @@ -47,23 +38,20 @@ import javax.inject.Inject; */ @MainThread @SysUISingleton -public class AccessibilityButtonModeObserver { +public class AccessibilityButtonModeObserver extends + SecureSettingsContentObserver<AccessibilityButtonModeObserver.ModeChangedListener> { + + private static final String TAG = "A11yButtonModeObserver"; private static final int ACCESSIBILITY_BUTTON_MODE_DEFAULT = ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; - private final ContentResolver mContentResolver; - @VisibleForTesting - final ContentObserver mContentObserver; - - private final List<ModeChangedListener> mListeners = new ArrayList<>(); - @Retention(RetentionPolicy.SOURCE) @IntDef({ ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU }) - private @interface AccessibilityButtonMode {} + public @interface AccessibilityButtonMode {} /** Listener for accessibility button mode changes. */ public interface ModeChangedListener { @@ -71,54 +59,20 @@ public class AccessibilityButtonModeObserver { /** * Called when accessibility button mode changes. * - * @param mode Current accessibility button mode. + * @param mode Current accessibility button mode */ void onAccessibilityButtonModeChanged(@AccessibilityButtonMode int mode); } @Inject public AccessibilityButtonModeObserver(Context context) { - mContentResolver = context.getContentResolver(); - mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) { - @Override - public void onChange(boolean selfChange) { - updateAccessibilityButtonModeChanged(); - } - }; + super(context, Settings.Secure.ACCESSIBILITY_BUTTON_MODE); } - /** - * Registers a listener to receive updates from settings key {@link - * Settings.Secure#ACCESSIBILITY_BUTTON_MODE}. - * - * @param listener A {@link ModeChangedListener} object. - */ - public void addListener(@NonNull ModeChangedListener listener) { - Objects.requireNonNull(listener, "listener must be non-null"); - - mListeners.add(listener); - - if (mListeners.size() == 1) { - mContentResolver.registerContentObserver( - Settings.Secure.getUriFor( - Settings.Secure.ACCESSIBILITY_BUTTON_MODE), /* notifyForDescendants= */ - false, mContentObserver); - } - } - - /** - * Unregisters a listener previously registered with {@link #addListener(ModeChangedListener)}. - * - * @param listener A {@link ModeChangedListener} object. - */ - public void removeListener(@NonNull ModeChangedListener listener) { - Objects.requireNonNull(listener, "listener must be non-null"); - - mListeners.remove(listener); - - if (mListeners.isEmpty()) { - mContentResolver.unregisterContentObserver(mContentObserver); - } + @Override + void onValueChanged(ModeChangedListener listener, String value) { + final int mode = parseAccessibilityButtonMode(value); + listener.onAccessibilityButtonModeChanged(mode); } /** @@ -126,17 +80,22 @@ public class AccessibilityButtonModeObserver { * * See {@link Settings.Secure#ACCESSIBILITY_BUTTON_MODE}. */ - @AccessibilityButtonMode public int getCurrentAccessibilityButtonMode() { - return Settings.Secure.getInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE, - ACCESSIBILITY_BUTTON_MODE_DEFAULT); + final String value = getSettingsValue(); + + return parseAccessibilityButtonMode(value); } - private void updateAccessibilityButtonModeChanged() { - final int mode = getCurrentAccessibilityButtonMode(); - final int listenerSize = mListeners.size(); - for (int i = 0; i < listenerSize; i++) { - mListeners.get(i).onAccessibilityButtonModeChanged(mode); + private int parseAccessibilityButtonMode(String value) { + int mode; + + try { + mode = Integer.parseInt(value); + } catch (NumberFormatException e) { + Log.e(TAG, "Invalid string for " + e); + mode = ACCESSIBILITY_BUTTON_MODE_DEFAULT; } + + return mode; } } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserver.java b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserver.java new file mode 100644 index 000000000000..b32ebccdd7db --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserver.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility; + +import android.content.Context; +import android.provider.Settings; + +import androidx.annotation.MainThread; +import androidx.annotation.Nullable; + +import com.android.systemui.dagger.SysUISingleton; + +import javax.inject.Inject; + +/** + * Controller for tracking the current accessibility button list. + * + * @see Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS + */ +@MainThread +@SysUISingleton +public class AccessibilityButtonTargetsObserver extends + SecureSettingsContentObserver<AccessibilityButtonTargetsObserver.TargetsChangedListener> { + + /** Listener for accessibility button targets changes. */ + public interface TargetsChangedListener { + + /** + * Called when accessibility button targets changes. + * + * @param targets Current content of {@link Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS} + */ + void onAccessibilityButtonTargetsChanged(String targets); + } + + @Inject + public AccessibilityButtonTargetsObserver(Context context) { + super(context, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS); + } + + @Override + void onValueChanged(TargetsChangedListener listener, String value) { + listener.onAccessibilityButtonTargetsChanged(value); + } + + /** Returns the current string from settings key + * {@link Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS}. */ + @Nullable + public String getCurrentAccessibilityButtonTargets() { + return getSettingsValue(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SecureSettingsContentObserver.java b/packages/SystemUI/src/com/android/systemui/accessibility/SecureSettingsContentObserver.java new file mode 100644 index 000000000000..4f8d8666a24a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/SecureSettingsContentObserver.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility; + +import android.content.ContentResolver; +import android.content.Context; +import android.database.ContentObserver; +import android.os.Handler; +import android.os.Looper; +import android.provider.Settings; + +import androidx.annotation.NonNull; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Provides basic methods for adding, removing arbitrary listeners and inquiry given {@code + * secureSettingsKey} value; it must comes from {@link Settings.Secure}. + * + * This abstract class is intended to be subclassed and specialized to maintain + * a registry of listeners of specific types and dispatch changes to them. + * + * @param <T> The listener type + */ +public abstract class SecureSettingsContentObserver<T> { + + private final ContentResolver mContentResolver; + @VisibleForTesting + final ContentObserver mContentObserver; + + private final String mKey; + + @VisibleForTesting + final List<T> mListeners = new ArrayList<>(); + + protected SecureSettingsContentObserver(Context context, String secureSettingsKey) { + mKey = secureSettingsKey; + mContentResolver = context.getContentResolver(); + mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) { + @Override + public void onChange(boolean selfChange) { + updateValueChanged(); + } + }; + } + + /** + * Registers a listener to receive updates from given settings key {@code secureSettingsKey}. + * + * @param listener A listener to be added to receive the changes + */ + public void addListener(@NonNull T listener) { + Objects.requireNonNull(listener, "listener must be non-null"); + + mListeners.add(listener); + + if (mListeners.size() == 1) { + mContentResolver.registerContentObserver( + Settings.Secure.getUriFor(mKey), /* notifyForDescendants= */ + false, mContentObserver); + } + } + + /** + * Unregisters a listener previously registered with {@link #addListener(T listener)}. + * + * @param listener A listener to be removed from receiving the changes + */ + public void removeListener(@NonNull T listener) { + Objects.requireNonNull(listener, "listener must be non-null"); + + mListeners.remove(listener); + + if (mListeners.isEmpty()) { + mContentResolver.unregisterContentObserver(mContentObserver); + } + } + + /** + * Gets the value from the current user's secure settings. + * + * See {@link Settings.Secure}. + */ + public final String getSettingsValue() { + return Settings.Secure.getString(mContentResolver, mKey); + } + + private void updateValueChanged() { + final String value = getSettingsValue(); + final int listenerSize = mListeners.size(); + for (int i = 0; i < listenerSize; i++) { + onValueChanged(mListeners.get(i), value); + } + } + + /** + * Called when the registered value from {@code secureSettingsKey} changes. + * + * @param listener A listener could be used to receive the updates + * @param value Content changed value from {@code secureSettingsKey} + */ + abstract void onValueChanged(T listener, String value); +} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java new file mode 100644 index 000000000000..fddbee393e4f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility.floatingmenu; + +import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; + +import android.content.Context; +import android.text.TextUtils; + +import androidx.annotation.MainThread; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.accessibility.AccessibilityButtonModeObserver; +import com.android.systemui.accessibility.AccessibilityButtonModeObserver.AccessibilityButtonMode; +import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver; +import com.android.systemui.dagger.SysUISingleton; + +import javax.inject.Inject; + +/** A controller to handle the lifecycle of accessibility floating menu. */ +@MainThread +@SysUISingleton +public class AccessibilityFloatingMenuController implements + AccessibilityButtonModeObserver.ModeChangedListener, + AccessibilityButtonTargetsObserver.TargetsChangedListener { + + private final Context mContext; + private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver; + private final AccessibilityButtonTargetsObserver mAccessibilityButtonTargetsObserver; + + @VisibleForTesting + IAccessibilityFloatingMenu mFloatingMenu; + private int mBtnMode; + private String mBtnTargets; + + @Inject + public AccessibilityFloatingMenuController(Context context, + AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver, + AccessibilityButtonModeObserver accessibilityButtonModeObserver) { + mContext = context; + mAccessibilityButtonTargetsObserver = accessibilityButtonTargetsObserver; + mAccessibilityButtonModeObserver = accessibilityButtonModeObserver; + + mAccessibilityButtonModeObserver.addListener(this); + mAccessibilityButtonTargetsObserver.addListener(this); + mBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode(); + mBtnTargets = mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets(); + + handleFloatingMenuVisibility(mBtnMode, mBtnTargets); + } + + /** + * Handles visibility of the accessibility floating menu when accessibility button mode changes. + * + * @param mode Current accessibility button mode. + */ + @Override + public void onAccessibilityButtonModeChanged(@AccessibilityButtonMode int mode) { + mBtnMode = mode; + handleFloatingMenuVisibility(mBtnMode, mBtnTargets); + } + + /** + * Handles visibility of the accessibility floating menu when accessibility button targets + * changes. + * List should come from {@link android.provider.Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS}. + * @param targets Current accessibility button list. + */ + @Override + public void onAccessibilityButtonTargetsChanged(String targets) { + mBtnTargets = targets; + handleFloatingMenuVisibility(mBtnMode, mBtnTargets); + } + + private void handleFloatingMenuVisibility(@AccessibilityButtonMode int mode, String targets) { + if (shouldShowFloatingMenu(mode, targets)) { + showFloatingMenu(); + } else { + destroyFloatingMenu(); + } + } + + private boolean shouldShowFloatingMenu(@AccessibilityButtonMode int mode, String targets) { + return mode == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU && !TextUtils.isEmpty(targets); + } + + private void showFloatingMenu() { + if (mFloatingMenu == null) { + mFloatingMenu = new AccessibilityFloatingMenu(mContext); + } + + mFloatingMenu.show(); + } + + private void destroyFloatingMenu() { + if (mFloatingMenu == null) { + return; + } + + mFloatingMenu.hide(); + mFloatingMenu = null; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java index d60122def85a..1a729295165c 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java @@ -47,8 +47,10 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.accessibility.AccessibilityButtonModeObserver; +import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver; import com.android.systemui.accessibility.ModeSwitchesController; import com.android.systemui.accessibility.SystemActions; +import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger; @@ -260,6 +262,16 @@ public class DependencyProvider { /** */ @Provides @SysUISingleton + public AccessibilityFloatingMenuController provideAccessibilityFloatingMenuController( + Context context, AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver, + AccessibilityButtonModeObserver accessibilityButtonModeObserver) { + return new AccessibilityFloatingMenuController(context, accessibilityButtonTargetsObserver, + accessibilityButtonModeObserver); + } + + /** */ + @Provides + @SysUISingleton public ConfigurationController provideConfigurationController(Context context) { return new ConfigurationControllerImpl(context); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index c6ef8a3d7ba4..6dd00a5ec70d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -144,6 +144,7 @@ import com.android.systemui.InitController; import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.SystemUI; +import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.charging.WirelessChargingAnimation; @@ -737,6 +738,7 @@ public class StatusBar extends SystemUI implements DemoMode, VisualStabilityManager visualStabilityManager, DeviceProvisionedController deviceProvisionedController, NavigationBarController navigationBarController, + AccessibilityFloatingMenuController accessibilityFloatingMenuController, Lazy<AssistManager> assistManagerLazy, ConfigurationController configurationController, NotificationShadeWindowController notificationShadeWindowController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java index b572c57590ae..17bb449ec5f4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java @@ -29,6 +29,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.InitController; +import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.classifier.FalsingCollector; @@ -164,6 +165,7 @@ public interface StatusBarPhoneModule { VisualStabilityManager visualStabilityManager, DeviceProvisionedController deviceProvisionedController, NavigationBarController navigationBarController, + AccessibilityFloatingMenuController accessibilityFloatingMenuController, Lazy<AssistManager> assistManagerLazy, ConfigurationController configurationController, NotificationShadeWindowController notificationShadeWindowController, @@ -245,6 +247,7 @@ public interface StatusBarPhoneModule { visualStabilityManager, deviceProvisionedController, navigationBarController, + accessibilityFloatingMenuController, assistManagerLazy, configurationController, notificationShadeWindowController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonModeObserverTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonModeObserverTest.java index 0eab0bb167b0..01b7adefbacf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonModeObserverTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonModeObserverTest.java @@ -17,6 +17,8 @@ package com.android.systemui.accessibility; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -52,7 +54,7 @@ public class AccessibilityButtonModeObserverTest extends SysuiTestCase { Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; @Before - public void setUpController() { + public void setUp() { Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_BUTTON_MODE, Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR); @@ -81,4 +83,15 @@ public class AccessibilityButtonModeObserverTest extends SysuiTestCase { verify(mListener, never()).onAccessibilityButtonModeChanged(anyInt()); } + + @Test + public void getCurrentAccessibilityButtonMode_expectedValue() { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_MODE, TEST_A11Y_BTN_MODE_VALUE); + + final int actualValue = + mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode(); + + assertThat(actualValue).isEqualTo(TEST_A11Y_BTN_MODE_VALUE); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserverTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserverTest.java new file mode 100644 index 000000000000..1e49fc998ea4 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/AccessibilityButtonTargetsObserverTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import android.provider.Settings; +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +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 AccessibilityButtonTargetsObserver}. */ +@RunWith(AndroidTestingRunner.class) +@SmallTest +public class AccessibilityButtonTargetsObserverTest extends SysuiTestCase { + + @Rule + public MockitoRule mockito = MockitoJUnit.rule(); + + @Mock + private AccessibilityButtonTargetsObserver.TargetsChangedListener mListener; + + private AccessibilityButtonTargetsObserver mAccessibilityButtonTargetsObserver; + + private static final String TEST_A11Y_BTN_TARGETS = "Magnification"; + + @Before + public void setUp() { + mAccessibilityButtonTargetsObserver = new AccessibilityButtonTargetsObserver(mContext); + } + + @Test + public void onChange_haveListener_invokeCallback() { + mAccessibilityButtonTargetsObserver.addListener(mListener); + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS); + + mAccessibilityButtonTargetsObserver.mContentObserver.onChange(false); + + verify(mListener).onAccessibilityButtonTargetsChanged(TEST_A11Y_BTN_TARGETS); + } + + @Test + public void onChange_listenerRemoved_noInvokeCallback() { + mAccessibilityButtonTargetsObserver.addListener(mListener); + mAccessibilityButtonTargetsObserver.removeListener(mListener); + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS); + + mAccessibilityButtonTargetsObserver.mContentObserver.onChange(false); + + verify(mListener, never()).onAccessibilityButtonTargetsChanged(anyString()); + } + + @Test + public void getCurrentAccessibilityButtonTargets_expectedValue() { + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS); + + final String actualValue = + mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets(); + + assertThat(actualValue).isEqualTo(TEST_A11Y_BTN_TARGETS); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/SecureSettingsContentObserverTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SecureSettingsContentObserverTest.java new file mode 100644 index 000000000000..5b1c441a71a1 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SecureSettingsContentObserverTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.provider.Settings; +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Test for {@link SecureSettingsContentObserver}. */ +@RunWith(AndroidTestingRunner.class) +@SmallTest +public class SecureSettingsContentObserverTest extends SysuiTestCase { + + private FakeSecureSettingsContentObserver mTestObserver; + + @Before + public void setUpObserver() { + mTestObserver = new FakeSecureSettingsContentObserver(mContext, + Settings.Secure.ACCESSIBILITY_BUTTON_MODE); + } + + @Test(expected = NullPointerException.class) + public void addNullListener_throwNPE() { + mTestObserver.addListener(null); + } + + @Test(expected = NullPointerException.class) + public void removeNullListener_throwNPE() { + mTestObserver.removeListener(null); + } + + @Test + public void checkValue() { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_MODE, 1); + + assertThat(mTestObserver.getSettingsValue()).isEqualTo("1"); + } + + + private static class FakeSecureSettingsContentObserver extends + SecureSettingsContentObserver<Object> { + + protected FakeSecureSettingsContentObserver(Context context, + String secureSettingsKey) { + super(context, secureSettingsKey); + } + + @Override + void onValueChanged(Object listener, String value) { + } + } +} 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 new file mode 100644 index 000000000000..0663f46a00e9 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility.floatingmenu; + +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.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.provider.Settings; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.Dependency; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.accessibility.AccessibilityButtonModeObserver; +import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Test for {@link AccessibilityFloatingMenuController}. */ +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +@SmallTest +public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { + + private static final String TEST_A11Y_BTN_TARGETS = "Magnification"; + + private AccessibilityFloatingMenuController mController; + private AccessibilityButtonTargetsObserver mTargetsObserver; + private AccessibilityButtonModeObserver mModeObserver; + + @Test + public void initController_registerListeners() { + mController = setUpController(); + + verify(mTargetsObserver).addListener( + any(AccessibilityButtonTargetsObserver.TargetsChangedListener.class)); + verify(mModeObserver).addListener( + any(AccessibilityButtonModeObserver.ModeChangedListener.class)); + } + + @Test + public void onAccessibilityButtonModeChanged_floatingModeAndHasButtonTargets_showWidget() { + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS); + mController = setUpController(); + + mController.onAccessibilityButtonModeChanged(ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU); + + assertThat(mController.mFloatingMenu).isNotNull(); + } + + @Test + public void onAccessibilityButtonModeChanged_floatingModeAndNoButtonTargets_destroyWidget() { + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, ""); + mController = setUpController(); + + mController.onAccessibilityButtonModeChanged(ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU); + + assertThat(mController.mFloatingMenu).isNull(); + } + + @Test + public void onAccessibilityButtonModeChanged_navBarModeAndHasButtonTargets_showWidget() { + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS); + mController = setUpController(); + + mController.onAccessibilityButtonModeChanged(ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR); + + assertThat(mController.mFloatingMenu).isNull(); + } + + @Test + public void onAccessibilityButtonModeChanged_navBarModeAndNoButtonTargets_destroyWidget() { + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, ""); + mController = setUpController(); + + mController.onAccessibilityButtonModeChanged(ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR); + + assertThat(mController.mFloatingMenu).isNull(); + } + + @Test + public void onAccessibilityButtonTargetsChanged_floatingModeAndHasButtonTargets_showWidget() { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU); + mController = setUpController(); + + mController.onAccessibilityButtonTargetsChanged(TEST_A11Y_BTN_TARGETS); + + assertThat(mController.mFloatingMenu).isNotNull(); + } + + @Test + public void onAccessibilityButtonTargetsChanged_floatingModeAndNoButtonTargets_destroyWidget() { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU); + mController = setUpController(); + + mController.onAccessibilityButtonTargetsChanged(""); + + assertThat(mController.mFloatingMenu).isNull(); + } + + @Test + public void onAccessibilityButtonTargetsChanged_navBarModeAndHasButtonTargets_showWidget() { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_MODE, + ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR); + mController = setUpController(); + + mController.onAccessibilityButtonTargetsChanged(TEST_A11Y_BTN_TARGETS); + + assertThat(mController.mFloatingMenu).isNull(); + } + + @Test + public void onAccessibilityButtonTargetsChanged_buttonModeAndNoButtonTargets_destroyWidget() { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_MODE, + ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR); + mController = setUpController(); + + mController.onAccessibilityButtonTargetsChanged(""); + + assertThat(mController.mFloatingMenu).isNull(); + } + + private AccessibilityFloatingMenuController setUpController() { + mTargetsObserver = spy(Dependency.get(AccessibilityButtonTargetsObserver.class)); + mModeObserver = spy(Dependency.get(AccessibilityButtonModeObserver.class)); + + return new AccessibilityFloatingMenuController(mContext, mTargetsObserver, mModeObserver); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 18bdd41dada0..0b454bfa8b69 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -78,6 +78,7 @@ import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.InitController; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.classifier.FalsingCollectorFake; @@ -210,6 +211,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private NotificationGutsManager mNotificationGutsManager; @Mock private NotificationMediaManager mNotificationMediaManager; @Mock private NavigationBarController mNavigationBarController; + @Mock private AccessibilityFloatingMenuController mAccessibilityFloatingMenuController; @Mock private BypassHeadsUpNotifier mBypassHeadsUpNotifier; @Mock private SysuiColorExtractor mColorExtractor; @Mock private ColorExtractor.GradientColors mGradientColors; @@ -385,6 +387,7 @@ public class StatusBarTest extends SysuiTestCase { mVisualStabilityManager, mDeviceProvisionedController, mNavigationBarController, + mAccessibilityFloatingMenuController, () -> mAssistManager, configurationController, mNotificationShadeWindowController, |