Merge changes from topic "accessibility_floating_menu_controller" into sc-dev

* changes:
  Set to accessibility floating menu mode when navigation mode is gestural
  Add the string for the accessibility floating menu tooltip
  Set default value of accessibility button mode
  Handle the phone get booted case to show accessibility floating menu
  Handle the basic logic to show or hide accessibility floating menu
  Observer for the accessibility button mode and notify its listeners for the changes
This commit is contained in:
Jason Hsu
2021-03-19 05:43:52 +00:00
committed by Android (Google) Code Review
20 changed files with 1036 additions and 3 deletions

View File

@@ -252,4 +252,8 @@
<!-- Default for Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW -->
<bool name="def_enable_non_resizable_multi_window">true</bool>
<!-- Default for Settings.Secure.ACCESSIBILITY_BUTTON_MODE -->
<integer name="def_accessibility_button_mode">1</integer>
</resources>

View File

@@ -3399,7 +3399,7 @@ public class SettingsProvider extends ContentProvider {
}
private final class UpgradeController {
private static final int SETTINGS_VERSION = 198;
private static final int SETTINGS_VERSION = 199;
private final int mUserId;
@@ -4897,6 +4897,36 @@ public class SettingsProvider extends ContentProvider {
currentVersion = 198;
}
if (currentVersion == 198) {
// Version 198: Set the default value for accessibility button. If the user
// uses accessibility button in the navigation bar to trigger their
// accessibility features (check if ACCESSIBILITY_BUTTON_TARGETS has value)
// then leave accessibility button mode in the navigation bar, otherwise, set it
// to the floating menu.
final SettingsState secureSettings = getSecureSettingsLocked(userId);
final Setting accessibilityButtonMode = secureSettings.getSettingLocked(
Secure.ACCESSIBILITY_BUTTON_MODE);
if (accessibilityButtonMode.isNull()) {
if (isAccessibilityButtonInNavigationBarOn(secureSettings)) {
secureSettings.insertSettingLocked(Secure.ACCESSIBILITY_BUTTON_MODE,
String.valueOf(
Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR),
/*tag= */ null, /* makeDefault= */ false,
SettingsState.SYSTEM_PACKAGE_NAME);
} else {
final int defAccessibilityButtonMode =
getContext().getResources().getInteger(
R.integer.def_accessibility_button_mode);
secureSettings.insertSettingLocked(Secure.ACCESSIBILITY_BUTTON_MODE,
String.valueOf(defAccessibilityButtonMode), /* tag= */
null, /* makeDefault= */ true,
SettingsState.SYSTEM_PACKAGE_NAME);
}
}
currentVersion = 199;
}
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
@@ -5075,5 +5105,15 @@ public class SettingsProvider extends ContentProvider {
}
return items;
}
private boolean isAccessibilityButtonInNavigationBarOn(SettingsState secureSettings) {
final boolean hasValueInA11yBtnTargets = !TextUtils.isEmpty(
secureSettings.getSettingLocked(
Secure.ACCESSIBILITY_BUTTON_TARGETS).getValue());
final int navigationMode = getContext().getResources().getInteger(
com.android.internal.R.integer.config_navBarInteractionMode);
return hasValueInA11yBtnTargets && (navigationMode != NAV_BAR_MODE_GESTURAL);
}
}
}

View File

@@ -2673,6 +2673,12 @@
<!-- Click action label for magnification switch. [CHAR LIMIT=NONE] -->
<string name="magnification_mode_switch_click_label">Switch</string>
<!-- Accessibility floating menu strings -->
<!-- Message for the accessibility floating button migration tooltip. It shows when the user use gestural navigation then upgrade their system. It will tell the user the accessibility gesture had been replaced by accessibility floating button. [CHAR LIMIT=100] -->
<string name="accessibility_floating_button_migration_tooltip">Accessibility button replaced the accessibility gesture\n\n<annotation id="link">View settings</annotation></string>
<!-- Message for the accessibility floating button docking tooltip. It shows when the user first time drag the button. It will tell the user about docking behavior. [CHAR LIMIT=70] -->
<string name="accessibility_floating_button_docking_tooltip">Move button to the edge to hide it temporarily</string>
<!-- Device Controls strings -->
<!-- Device Controls empty state, title [CHAR LIMIT=30] -->
<string name="quick_controls_title">Device controls</string>

View File

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

View File

@@ -0,0 +1,101 @@
/*
* 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 android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
import android.annotation.IntDef;
import android.annotation.MainThread;
import android.content.Context;
import android.provider.Settings;
import android.util.Log;
import com.android.systemui.dagger.SysUISingleton;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.inject.Inject;
/**
* Observes changes of the accessibility button mode
* {@link Settings.Secure#ACCESSIBILITY_BUTTON_MODE} and notify its listeners.
*/
@MainThread
@SysUISingleton
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;
@Retention(RetentionPolicy.SOURCE)
@IntDef({
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR,
ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU
})
public @interface AccessibilityButtonMode {}
/** Listener for accessibility button mode changes. */
public interface ModeChangedListener {
/**
* Called when accessibility button mode changes.
*
* @param mode Current accessibility button mode
*/
void onAccessibilityButtonModeChanged(@AccessibilityButtonMode int mode);
}
@Inject
public AccessibilityButtonModeObserver(Context context) {
super(context, Settings.Secure.ACCESSIBILITY_BUTTON_MODE);
}
@Override
void onValueChanged(ModeChangedListener listener, String value) {
final int mode = parseAccessibilityButtonMode(value);
listener.onAccessibilityButtonModeChanged(mode);
}
/**
* Gets the current accessibility button mode from the current user's settings.
*
* See {@link Settings.Secure#ACCESSIBILITY_BUTTON_MODE}.
*/
public int getCurrentAccessibilityButtonMode() {
final String value = getSettingsValue();
return parseAccessibilityButtonMode(value);
}
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;
}
}

View File

@@ -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();
}
}

View File

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

View File

@@ -0,0 +1,145 @@
/*
* 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 android.view.accessibility.AccessibilityManager;
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,
AccessibilityManager.AccessibilityStateChangeListener {
private final Context mContext;
private final AccessibilityManager mAccessibilityManager;
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;
mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class);
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);
}
}
/**
* 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);
}
/**
* 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();
} 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;
}
}

View File

@@ -46,8 +46,11 @@ import com.android.keyguard.ViewMediatorCallback;
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;
@@ -213,6 +216,7 @@ public class DependencyProvider {
MetricsLogger metricsLogger,
OverviewProxyService overviewProxyService,
NavigationModeController navigationModeController,
AccessibilityButtonModeObserver accessibilityButtonModeObserver,
StatusBarStateController statusBarStateController,
SysUiState sysUiFlagsContainer,
BroadcastDispatcher broadcastDispatcher,
@@ -237,6 +241,7 @@ public class DependencyProvider {
metricsLogger,
overviewProxyService,
navigationModeController,
accessibilityButtonModeObserver,
statusBarStateController,
sysUiFlagsContainer,
broadcastDispatcher,
@@ -254,6 +259,16 @@ public class DependencyProvider {
configurationController);
}
/** */
@Provides
@SysUISingleton
public AccessibilityFloatingMenuController provideAccessibilityFloatingMenuController(
Context context, AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver,
AccessibilityButtonModeObserver accessibilityButtonModeObserver) {
return new AccessibilityFloatingMenuController(context, accessibilityButtonTargetsObserver,
accessibilityButtonModeObserver);
}
/** */
@Provides
@SysUISingleton

View File

@@ -23,6 +23,7 @@ import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.WindowType;
import static android.app.StatusBarManager.WindowVisibleState;
import static android.app.StatusBarManager.windowStateToString;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.containsType;
@@ -113,6 +114,7 @@ import com.android.internal.util.LatencyTracker;
import com.android.internal.view.AppearanceRegion;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.SystemActions;
import com.android.systemui.assist.AssistHandleViewController;
import com.android.systemui.assist.AssistManager;
@@ -158,7 +160,8 @@ import dagger.Lazy;
* Contains logic for a navigation bar view.
*/
public class NavigationBar implements View.OnAttachStateChangeListener,
Callbacks, NavigationModeController.ModeChangedListener, DisplayManager.DisplayListener {
Callbacks, NavigationModeController.ModeChangedListener,
AccessibilityButtonModeObserver.ModeChangedListener, DisplayManager.DisplayListener {
public static final String TAG = "NavigationBar";
private static final boolean DEBUG = false;
@@ -186,6 +189,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private final NotificationRemoteInputManager mNotificationRemoteInputManager;
private final OverviewProxyService mOverviewProxyService;
private final NavigationModeController mNavigationModeController;
private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
private final BroadcastDispatcher mBroadcastDispatcher;
private final CommandQueue mCommandQueue;
private final Optional<Pip> mPipOptional;
@@ -226,6 +230,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private boolean mTransientShown;
private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
private int mA11yBtnMode;
private LightBarController mLightBarController;
private AutoHideController mAutoHideController;
@@ -443,6 +448,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
MetricsLogger metricsLogger,
OverviewProxyService overviewProxyService,
NavigationModeController navigationModeController,
AccessibilityButtonModeObserver accessibilityButtonModeObserver,
StatusBarStateController statusBarStateController,
SysUiState sysUiFlagsContainer,
BroadcastDispatcher broadcastDispatcher,
@@ -470,7 +476,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mNotificationRemoteInputManager = notificationRemoteInputManager;
mOverviewProxyService = overviewProxyService;
mNavigationModeController = navigationModeController;
mNavBarMode = navigationModeController.addListener(this);
mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
mBroadcastDispatcher = broadcastDispatcher;
mCommandQueue = commandQueue;
mPipOptional = pipOptional;
@@ -480,6 +486,10 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mHandler = mainHandler;
mNavbarOverlayController = navbarOverlayController;
mUiEventLogger = uiEventLogger;
mNavBarMode = mNavigationModeController.addListener(this);
mAccessibilityButtonModeObserver.addListener(this);
mA11yBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode();
}
public View getView() {
@@ -552,6 +562,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mIsCurrentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
mDeviceProvisionedController.addCallback(mUserSetupListener);
setAccessibilityFloatingMenuModeIfNeeded();
return barView;
}
@@ -560,6 +572,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mContext.getSystemService(WindowManager.class).removeViewImmediate(
mNavigationBarView.getRootView());
mNavigationModeController.removeListener(this);
mAccessibilityButtonModeObserver.removeListener(this);
mAccessibilityManagerWrapper.removeCallback(mAccessibilityListener);
mContentResolver.unregisterContentObserver(mAssistContentObserver);
@@ -1395,6 +1408,13 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
updateSystemUiStateFlags(a11yFlags);
}
private void setAccessibilityFloatingMenuModeIfNeeded() {
if (QuickStepContract.isGesturalMode(mNavBarMode)) {
Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
}
}
public void updateSystemUiStateFlags(int a11yFlags) {
if (a11yFlags < 0) {
a11yFlags = getA11yButtonState(null);
@@ -1450,6 +1470,12 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
outFeedbackEnabled[0] = feedbackEnabled;
}
// If accessibility button is floating menu mode, click and long click state should be
// disabled.
if (mA11yBtnMode == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
return 0;
}
return (requestingServices >= 1 ? SYSUI_STATE_A11Y_BUTTON_CLICKABLE : 0)
| (requestingServices >= 2 ? SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE : 0);
}
@@ -1534,12 +1560,19 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
}
}
updateScreenPinningGestures();
setAccessibilityFloatingMenuModeIfNeeded();
if (!canShowSecondaryHandle()) {
resetSecondaryHandle();
}
}
@Override
public void onAccessibilityButtonModeChanged(int mode) {
mA11yBtnMode = mode;
updateAccessibilityServicesState(mAccessibilityManager);
}
public void disableAnimationsDuringHide(long delay) {
mNavigationBarView.setLayoutTransitionsEnabled(false);
mNavigationBarView.postDelayed(() -> mNavigationBarView.setLayoutTransitionsEnabled(true),

View File

@@ -43,6 +43,7 @@ import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.RegisterStatusBarResult;
import com.android.settingslib.applications.InterestingConfigChanges;
import com.android.systemui.Dumpable;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.SystemActions;
import com.android.systemui.assist.AssistHandleViewController;
import com.android.systemui.assist.AssistManager;
@@ -91,6 +92,7 @@ public class NavigationBarController implements Callbacks,
private final MetricsLogger mMetricsLogger;
private final OverviewProxyService mOverviewProxyService;
private final NavigationModeController mNavigationModeController;
private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
private final StatusBarStateController mStatusBarStateController;
private final SysUiState mSysUiFlagsContainer;
private final BroadcastDispatcher mBroadcastDispatcher;
@@ -127,6 +129,7 @@ public class NavigationBarController implements Callbacks,
MetricsLogger metricsLogger,
OverviewProxyService overviewProxyService,
NavigationModeController navigationModeController,
AccessibilityButtonModeObserver accessibilityButtonModeObserver,
StatusBarStateController statusBarStateController,
SysUiState sysUiFlagsContainer,
BroadcastDispatcher broadcastDispatcher,
@@ -151,6 +154,7 @@ public class NavigationBarController implements Callbacks,
mMetricsLogger = metricsLogger;
mOverviewProxyService = overviewProxyService;
mNavigationModeController = navigationModeController;
mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
mStatusBarStateController = statusBarStateController;
mSysUiFlagsContainer = sysUiFlagsContainer;
mBroadcastDispatcher = broadcastDispatcher;
@@ -289,6 +293,7 @@ public class NavigationBarController implements Callbacks,
mMetricsLogger,
mOverviewProxyService,
mNavigationModeController,
mAccessibilityButtonModeObserver,
mStatusBarStateController,
mSysUiFlagsContainer,
mBroadcastDispatcher,

View File

@@ -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,

View File

@@ -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,

View File

@@ -0,0 +1,97 @@
/*
* 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.anyInt;
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;
@RunWith(AndroidTestingRunner.class)
@SmallTest
public class AccessibilityButtonModeObserverTest extends SysuiTestCase {
@Rule
public MockitoRule mockito = MockitoJUnit.rule();
@Mock
private AccessibilityButtonModeObserver.ModeChangedListener mListener;
private AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
private static final int TEST_A11Y_BTN_MODE_VALUE =
Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
@Before
public void setUp() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
mAccessibilityButtonModeObserver = new AccessibilityButtonModeObserver(mContext);
}
@Test
public void onChange_haveListener_invokeCallback() {
mAccessibilityButtonModeObserver.addListener(mListener);
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, TEST_A11Y_BTN_MODE_VALUE);
mAccessibilityButtonModeObserver.mContentObserver.onChange(false);
verify(mListener).onAccessibilityButtonModeChanged(TEST_A11Y_BTN_MODE_VALUE);
}
@Test
public void onChange_noListener_noInvokeCallback() {
mAccessibilityButtonModeObserver.addListener(mListener);
mAccessibilityButtonModeObserver.removeListener(mListener);
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, TEST_A11Y_BTN_MODE_VALUE);
mAccessibilityButtonModeObserver.mContentObserver.onChange(false);
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);
}
}

View File

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

View File

@@ -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) {
}
}
}

View File

@@ -0,0 +1,204 @@
/*
* 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 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.systemui.Dependency;
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)
@TestableLooper.RunWithLooper
@SmallTest
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() {
mController = setUpController();
verify(mTargetsObserver).addListener(
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
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));
mContext.addMockSystemService(AccessibilityManager.class, mMockA11yManager);
return new AccessibilityFloatingMenuController(mContext, mTargetsObserver,
mModeObserver);
}
}

View File

@@ -45,6 +45,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.SystemActions;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -93,6 +94,7 @@ public class NavigationBarControllerTest extends SysuiTestCase {
mock(MetricsLogger.class),
mock(OverviewProxyService.class),
mock(NavigationModeController.class),
mock(AccessibilityButtonModeObserver.class),
mock(StatusBarStateController.class),
mock(SysUiState.class),
mock(BroadcastDispatcher.class),

View File

@@ -67,6 +67,7 @@ import com.android.internal.logging.UiEventLogger;
import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.SysuiTestableContext;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.SystemActions;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -259,6 +260,7 @@ public class NavigationBarTest extends SysuiTestCase {
new MetricsLogger(),
mOverviewProxyService,
mock(NavigationModeController.class),
mock(AccessibilityButtonModeObserver.class),
mock(StatusBarStateController.class),
mMockSysUiState,
mBroadcastDispatcher,

View File

@@ -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,