Loading core/java/com/android/internal/accessibility/util/ShortcutUtils.java +64 −12 Original line number Diff line number Diff line Loading @@ -16,18 +16,31 @@ package com.android.internal.accessibility.util; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType.INVISIBLE_TOGGLE; import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR; import static com.android.internal.accessibility.common.ShortcutConstants.USER_SHORTCUT_TYPES; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.QUICK_SETTINGS; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.TRIPLETAP; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.TWOFINGER_DOUBLETAP; import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.ComponentName; import android.content.Context; import android.provider.Settings; import android.text.TextUtils; import android.util.ArraySet; import android.util.Slog; import android.view.accessibility.AccessibilityManager; import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; Loading @@ -45,6 +58,7 @@ public final class ShortcutUtils { private static final TextUtils.SimpleStringSplitter sStringColonSplitter = new TextUtils.SimpleStringSplitter(SERVICES_SEPARATOR); private static final String TAG = "AccessibilityShortcutUtils"; /** * Opts in component id into colon-separated {@link UserShortcutType} Loading Loading @@ -164,17 +178,17 @@ public final class ShortcutUtils { */ public static String convertToKey(@UserShortcutType int type) { switch (type) { case UserShortcutType.SOFTWARE: case SOFTWARE: return Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS; case UserShortcutType.GESTURE: case GESTURE: return Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS; case UserShortcutType.HARDWARE: case HARDWARE: return Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE; case UserShortcutType.TRIPLETAP: case TRIPLETAP: return Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED; case UserShortcutType.TWOFINGER_DOUBLETAP: case TWOFINGER_DOUBLETAP: return Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED; case UserShortcutType.QUICK_SETTINGS: case QUICK_SETTINGS: return Settings.Secure.ACCESSIBILITY_QS_TARGETS; default: throw new IllegalArgumentException( Loading @@ -191,14 +205,14 @@ public final class ShortcutUtils { @UserShortcutType public static int convertToType(String key) { return switch (key) { case Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS -> UserShortcutType.SOFTWARE; case Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS -> UserShortcutType.GESTURE; case Settings.Secure.ACCESSIBILITY_QS_TARGETS -> UserShortcutType.QUICK_SETTINGS; case Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE -> UserShortcutType.HARDWARE; case Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS -> SOFTWARE; case Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS -> GESTURE; case Settings.Secure.ACCESSIBILITY_QS_TARGETS -> QUICK_SETTINGS; case Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE -> HARDWARE; case Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED -> UserShortcutType.TRIPLETAP; TRIPLETAP; case Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED -> UserShortcutType.TWOFINGER_DOUBLETAP; TWOFINGER_DOUBLETAP; default -> throw new IllegalArgumentException( "Unsupported user shortcut key: " + key); }; Loading Loading @@ -296,4 +310,42 @@ public final class ShortcutUtils { return Collections.unmodifiableSet(targets); } } /** * Retrieves the button mode of the provided context. * Returns -1 if the button mode is undefined. * Valid button modes: * {@link Settings.Secure#ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR}, * {@link Settings.Secure#ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU}, * {@link Settings.Secure#ACCESSIBILITY_BUTTON_MODE_GESTURE} */ public static int getButtonMode(Context context, @UserIdInt int userId) { return Settings.Secure.getIntForUser(context.getContentResolver(), ACCESSIBILITY_BUTTON_MODE, /* default value = */ -1, userId); } /** * Sets the button mode of the provided context. * Must be a valid button mode, or it will return false. * Returns true if the setting was changed, false otherwise. * Valid button modes: * {@link Settings.Secure#ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR}, * {@link Settings.Secure#ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU}, * {@link Settings.Secure#ACCESSIBILITY_BUTTON_MODE_GESTURE} */ public static boolean setButtonMode(Context context, int mode, @UserIdInt int userId) { // Input validation if (getButtonMode(context, userId) == mode) { return false; } if ((mode & (ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR | ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU | ACCESSIBILITY_BUTTON_MODE_GESTURE)) != mode) { Slog.w(TAG, "Tried to set button mode to unexpected value " + mode); return false; } return Settings.Secure.putIntForUser( context.getContentResolver(), ACCESSIBILITY_BUTTON_MODE, mode, userId); } } packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java +0 −38 Original line number Diff line number Diff line Loading @@ -16,10 +16,6 @@ package com.android.systemui.navigationbar; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; import static com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler.DEBUG_MISSING_GESTURE_TAG; import static com.android.systemui.shared.recents.utilities.Utilities.isLargeScreen; import static com.android.wm.shell.Flags.enableTaskbarNavbarUnification; Loading @@ -32,8 +28,6 @@ import android.hardware.display.DisplayManager; import android.os.Bundle; import android.os.RemoteException; import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; import android.util.Log; import android.util.SparseArray; import android.util.SparseBooleanArray; Loading @@ -59,7 +53,6 @@ import com.android.systemui.navigationbar.views.NavigationBarView; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.settings.DisplayTracker; import com.android.systemui.shared.statusbar.phone.BarTransitions.TransitionMode; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.TaskStackChangeListeners; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.AutoHideController; Loading Loading @@ -192,7 +185,6 @@ public class NavigationBarControllerImpl implements } final int oldMode = mNavMode; mNavMode = mode; updateAccessibilityButtonModeIfNeeded(); mExecutor.execute(() -> { // create/destroy nav bar based on nav mode only in unfolded state Loading @@ -209,34 +201,6 @@ public class NavigationBarControllerImpl implements }); } private void updateAccessibilityButtonModeIfNeeded() { final int mode = mSecureSettings.getIntForUser( Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT); // ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU is compatible under gestural or non-gestural // mode, so we don't need to update it. if (mode == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) { return; } // ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR is incompatible under gestural mode. Need to // force update to ACCESSIBILITY_BUTTON_MODE_GESTURE. if (QuickStepContract.isGesturalMode(mNavMode) && mode == ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR) { mSecureSettings.putIntForUser( Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_GESTURE, UserHandle.USER_CURRENT); // ACCESSIBILITY_BUTTON_MODE_GESTURE is incompatible under non gestural mode. Need to // force update to ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR. } else if (!QuickStepContract.isGesturalMode(mNavMode) && mode == ACCESSIBILITY_BUTTON_MODE_GESTURE) { mSecureSettings.putIntForUser( Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT); } } private boolean shouldCreateNavBarAndTaskBar(int displayId) { if (mHasNavBar.indexOfKey(displayId) > -1) { return mHasNavBar.get(displayId); Loading Loading @@ -353,8 +317,6 @@ public class NavigationBarControllerImpl implements @Override public void createNavigationBars(final boolean includeDefaultDisplay, RegisterStatusBarResult result) { updateAccessibilityButtonModeIfNeeded(); // Don't need to create nav bar on the default display if we initialize TaskBar. final boolean shouldCreateDefaultNavbar = includeDefaultDisplay && !initializeTaskbarIfNecessary(); Loading services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +103 −2 Original line number Diff line number Diff line Loading @@ -38,7 +38,11 @@ import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAG import static android.companion.virtual.VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED; import static android.companion.virtual.VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID; import static android.content.Context.DEVICE_ID_DEFAULT; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; import static android.view.accessibility.AccessibilityManager.FlashNotificationReason; import static com.android.hardware.input.Flags.keyboardA11yMouseKeys; Loading @@ -55,6 +59,7 @@ import static com.android.internal.accessibility.common.ShortcutConstants.UserSh import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.TRIPLETAP; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.TWOFINGER_DOUBLETAP; import static com.android.internal.accessibility.util.AccessibilityStatsLogUtils.logAccessibilityShortcutActivated; import static com.android.internal.accessibility.util.AccessibilityUtils.isUserSetupCompleted; import static com.android.internal.util.FunctionalUtils.ignoreRemoteException; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static com.android.server.accessibility.AccessibilityUserState.doesShortcutTargetsStringContain; Loading Loading @@ -937,6 +942,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } case Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS, Settings.Secure.ACCESSIBILITY_QS_TARGETS, Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE -> restoreShortcutTargets(newValue, Loading Loading @@ -1995,6 +2001,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub // Accessibility Menu component disabled. disableAccessibilityMenuToMigrateIfNeeded(); // As an initialization step, update the shortcuts for the current user. updateShortcutsForCurrentNavigationMode(); if (announceNewUser) { // Schedule announcement of the current user if needed. mMainHandler.sendMessageDelayed( Loading Loading @@ -2216,6 +2225,69 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mProxyManager.clearCacheLocked(); } @VisibleForTesting void updateShortcutsForCurrentNavigationMode() { synchronized (mLock) { AccessibilityUserState userState = getCurrentUserStateLocked(); if (!isUserSetupCompleted(mContext)) { return; } final boolean isInGesturalNavigation = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.NAVIGATION_MODE, -1, userState.mUserId) == NAV_BAR_MODE_GESTURAL; Set<String> gestureTargets = userState.getShortcutTargetsLocked(GESTURE); Set<String> softwareTargets = userState.getShortcutTargetsLocked(SOFTWARE); int buttonMode = ShortcutUtils.getButtonMode(mContext, userState.mUserId); if (android.provider.Flags.a11yStandaloneGestureEnabled()) { if (isInGesturalNavigation) { if (buttonMode == ACCESSIBILITY_BUTTON_MODE_GESTURE) { // GESTURE button mode indicates migrating from old version // User was using gesture, so move all targets into gesture gestureTargets.addAll(softwareTargets); softwareTargets.clear(); } buttonMode = ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; } else { // Only change the current button mode if there are gesture targets // (indicating the user came from gesture mode or is migrating) if (!gestureTargets.isEmpty()) { buttonMode = softwareTargets.isEmpty() ? ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR : ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; softwareTargets.addAll(gestureTargets); gestureTargets.clear(); } } } else { if (!gestureTargets.isEmpty()) { // Adjust button mode before clearing out gesture targets if (!softwareTargets.isEmpty()) { buttonMode = ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; } else if (isInGesturalNavigation) { buttonMode = ACCESSIBILITY_BUTTON_MODE_GESTURE; } else { buttonMode = ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; } softwareTargets.addAll(gestureTargets); gestureTargets.clear(); } else if (buttonMode != ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) { buttonMode = isInGesturalNavigation ? ACCESSIBILITY_BUTTON_MODE_GESTURE : ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; } } updateShortcutTargetSets(userState, Set.of( Pair.create(gestureTargets, GESTURE), Pair.create(softwareTargets, SOFTWARE) )); ShortcutUtils.setButtonMode(mContext, buttonMode, userState.mUserId); } } private void notifyMagnificationChangedLocked(int displayId, @NonNull Region region, @NonNull MagnificationConfig config) { final AccessibilityUserState state = getCurrentUserStateLocked(); Loading Loading @@ -3646,6 +3718,23 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub scheduleNotifyClientsOfServicesStateChangeLocked(userState); } private void updateShortcutTargetSets(AccessibilityUserState userState, Set<Pair<Set<String>, Integer>> targetSets) { boolean somethingChanged = false; for (Pair<Set<String>, Integer> pair : targetSets) { Set<String> targets = pair.first; int type = pair.second; if (userState.updateShortcutTargetsLocked(targets, type)) { somethingChanged = true; persistColonDelimitedSetToSettingLocked(ShortcutUtils.convertToKey(type), userState.mUserId, targets, str -> str); } } if (somethingChanged) { scheduleNotifyClientsOfServicesStateChangeLocked(userState); } } /** * 1) Check if the service assigned to accessibility button target sdk version > Q. * If it isn't, remove it from the list and associated setting. Loading Loading @@ -5505,6 +5594,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private final Uri mMouseKeysUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_MOUSE_KEYS_ENABLED); private final Uri mNavigationModeUri = Settings.Secure.getUriFor( Settings.Secure.NAVIGATION_MODE); private final Uri mUserSetupCompleteUri = Settings.Secure.getUriFor( Settings.Secure.USER_SETUP_COMPLETE); public AccessibilityContentObserver(Handler handler) { super(handler); } Loading Loading @@ -5555,6 +5650,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mAlwaysOnMagnificationUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mMouseKeysUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mNavigationModeUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mUserSetupCompleteUri, false, this, UserHandle.USER_ALL); } @Override Loading Loading @@ -5639,6 +5738,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (readMouseKeysEnabledLocked(userState)) { onUserStateChangedLocked(userState); } } else if (mNavigationModeUri.equals(uri) || mUserSetupCompleteUri.equals(uri)) { updateShortcutsForCurrentNavigationMode(); } } } Loading services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java +4 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ import android.view.accessibility.IAccessibilityManagerClient; import com.android.internal.R; import com.android.internal.accessibility.AccessibilityShortcutController; import com.android.internal.accessibility.util.ShortcutUtils; import java.io.FileDescriptor; import java.io.PrintWriter; Loading Loading @@ -579,6 +580,9 @@ class AccessibilityUserState { .append(String.valueOf(mAlwaysOnMagnificationEnabled)); pw.append("}"); pw.println(); pw.append(" button mode: "); pw.append(String.valueOf(ShortcutUtils.getButtonMode(mContext, mUserId))); pw.println(); dumpShortcutTargets(pw, HARDWARE, "shortcut key"); dumpShortcutTargets(pw, SOFTWARE, "button"); pw.append(" button target:{").append(mTargetAssignedToAccessibilityButton); Loading services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java +215 −49 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
core/java/com/android/internal/accessibility/util/ShortcutUtils.java +64 −12 Original line number Diff line number Diff line Loading @@ -16,18 +16,31 @@ package com.android.internal.accessibility.util; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType.INVISIBLE_TOGGLE; import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR; import static com.android.internal.accessibility.common.ShortcutConstants.USER_SHORTCUT_TYPES; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.QUICK_SETTINGS; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.TRIPLETAP; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.TWOFINGER_DOUBLETAP; import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.ComponentName; import android.content.Context; import android.provider.Settings; import android.text.TextUtils; import android.util.ArraySet; import android.util.Slog; import android.view.accessibility.AccessibilityManager; import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; Loading @@ -45,6 +58,7 @@ public final class ShortcutUtils { private static final TextUtils.SimpleStringSplitter sStringColonSplitter = new TextUtils.SimpleStringSplitter(SERVICES_SEPARATOR); private static final String TAG = "AccessibilityShortcutUtils"; /** * Opts in component id into colon-separated {@link UserShortcutType} Loading Loading @@ -164,17 +178,17 @@ public final class ShortcutUtils { */ public static String convertToKey(@UserShortcutType int type) { switch (type) { case UserShortcutType.SOFTWARE: case SOFTWARE: return Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS; case UserShortcutType.GESTURE: case GESTURE: return Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS; case UserShortcutType.HARDWARE: case HARDWARE: return Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE; case UserShortcutType.TRIPLETAP: case TRIPLETAP: return Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED; case UserShortcutType.TWOFINGER_DOUBLETAP: case TWOFINGER_DOUBLETAP: return Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED; case UserShortcutType.QUICK_SETTINGS: case QUICK_SETTINGS: return Settings.Secure.ACCESSIBILITY_QS_TARGETS; default: throw new IllegalArgumentException( Loading @@ -191,14 +205,14 @@ public final class ShortcutUtils { @UserShortcutType public static int convertToType(String key) { return switch (key) { case Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS -> UserShortcutType.SOFTWARE; case Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS -> UserShortcutType.GESTURE; case Settings.Secure.ACCESSIBILITY_QS_TARGETS -> UserShortcutType.QUICK_SETTINGS; case Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE -> UserShortcutType.HARDWARE; case Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS -> SOFTWARE; case Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS -> GESTURE; case Settings.Secure.ACCESSIBILITY_QS_TARGETS -> QUICK_SETTINGS; case Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE -> HARDWARE; case Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED -> UserShortcutType.TRIPLETAP; TRIPLETAP; case Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED -> UserShortcutType.TWOFINGER_DOUBLETAP; TWOFINGER_DOUBLETAP; default -> throw new IllegalArgumentException( "Unsupported user shortcut key: " + key); }; Loading Loading @@ -296,4 +310,42 @@ public final class ShortcutUtils { return Collections.unmodifiableSet(targets); } } /** * Retrieves the button mode of the provided context. * Returns -1 if the button mode is undefined. * Valid button modes: * {@link Settings.Secure#ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR}, * {@link Settings.Secure#ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU}, * {@link Settings.Secure#ACCESSIBILITY_BUTTON_MODE_GESTURE} */ public static int getButtonMode(Context context, @UserIdInt int userId) { return Settings.Secure.getIntForUser(context.getContentResolver(), ACCESSIBILITY_BUTTON_MODE, /* default value = */ -1, userId); } /** * Sets the button mode of the provided context. * Must be a valid button mode, or it will return false. * Returns true if the setting was changed, false otherwise. * Valid button modes: * {@link Settings.Secure#ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR}, * {@link Settings.Secure#ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU}, * {@link Settings.Secure#ACCESSIBILITY_BUTTON_MODE_GESTURE} */ public static boolean setButtonMode(Context context, int mode, @UserIdInt int userId) { // Input validation if (getButtonMode(context, userId) == mode) { return false; } if ((mode & (ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR | ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU | ACCESSIBILITY_BUTTON_MODE_GESTURE)) != mode) { Slog.w(TAG, "Tried to set button mode to unexpected value " + mode); return false; } return Settings.Secure.putIntForUser( context.getContentResolver(), ACCESSIBILITY_BUTTON_MODE, mode, userId); } }
packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java +0 −38 Original line number Diff line number Diff line Loading @@ -16,10 +16,6 @@ package com.android.systemui.navigationbar; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; import static com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler.DEBUG_MISSING_GESTURE_TAG; import static com.android.systemui.shared.recents.utilities.Utilities.isLargeScreen; import static com.android.wm.shell.Flags.enableTaskbarNavbarUnification; Loading @@ -32,8 +28,6 @@ import android.hardware.display.DisplayManager; import android.os.Bundle; import android.os.RemoteException; import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; import android.util.Log; import android.util.SparseArray; import android.util.SparseBooleanArray; Loading @@ -59,7 +53,6 @@ import com.android.systemui.navigationbar.views.NavigationBarView; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.settings.DisplayTracker; import com.android.systemui.shared.statusbar.phone.BarTransitions.TransitionMode; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.TaskStackChangeListeners; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.AutoHideController; Loading Loading @@ -192,7 +185,6 @@ public class NavigationBarControllerImpl implements } final int oldMode = mNavMode; mNavMode = mode; updateAccessibilityButtonModeIfNeeded(); mExecutor.execute(() -> { // create/destroy nav bar based on nav mode only in unfolded state Loading @@ -209,34 +201,6 @@ public class NavigationBarControllerImpl implements }); } private void updateAccessibilityButtonModeIfNeeded() { final int mode = mSecureSettings.getIntForUser( Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT); // ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU is compatible under gestural or non-gestural // mode, so we don't need to update it. if (mode == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) { return; } // ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR is incompatible under gestural mode. Need to // force update to ACCESSIBILITY_BUTTON_MODE_GESTURE. if (QuickStepContract.isGesturalMode(mNavMode) && mode == ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR) { mSecureSettings.putIntForUser( Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_GESTURE, UserHandle.USER_CURRENT); // ACCESSIBILITY_BUTTON_MODE_GESTURE is incompatible under non gestural mode. Need to // force update to ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR. } else if (!QuickStepContract.isGesturalMode(mNavMode) && mode == ACCESSIBILITY_BUTTON_MODE_GESTURE) { mSecureSettings.putIntForUser( Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT); } } private boolean shouldCreateNavBarAndTaskBar(int displayId) { if (mHasNavBar.indexOfKey(displayId) > -1) { return mHasNavBar.get(displayId); Loading Loading @@ -353,8 +317,6 @@ public class NavigationBarControllerImpl implements @Override public void createNavigationBars(final boolean includeDefaultDisplay, RegisterStatusBarResult result) { updateAccessibilityButtonModeIfNeeded(); // Don't need to create nav bar on the default display if we initialize TaskBar. final boolean shouldCreateDefaultNavbar = includeDefaultDisplay && !initializeTaskbarIfNecessary(); Loading
services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +103 −2 Original line number Diff line number Diff line Loading @@ -38,7 +38,11 @@ import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAG import static android.companion.virtual.VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED; import static android.companion.virtual.VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID; import static android.content.Context.DEVICE_ID_DEFAULT; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; import static android.view.accessibility.AccessibilityManager.FlashNotificationReason; import static com.android.hardware.input.Flags.keyboardA11yMouseKeys; Loading @@ -55,6 +59,7 @@ import static com.android.internal.accessibility.common.ShortcutConstants.UserSh import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.TRIPLETAP; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.TWOFINGER_DOUBLETAP; import static com.android.internal.accessibility.util.AccessibilityStatsLogUtils.logAccessibilityShortcutActivated; import static com.android.internal.accessibility.util.AccessibilityUtils.isUserSetupCompleted; import static com.android.internal.util.FunctionalUtils.ignoreRemoteException; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static com.android.server.accessibility.AccessibilityUserState.doesShortcutTargetsStringContain; Loading Loading @@ -937,6 +942,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } case Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS, Settings.Secure.ACCESSIBILITY_QS_TARGETS, Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE -> restoreShortcutTargets(newValue, Loading Loading @@ -1995,6 +2001,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub // Accessibility Menu component disabled. disableAccessibilityMenuToMigrateIfNeeded(); // As an initialization step, update the shortcuts for the current user. updateShortcutsForCurrentNavigationMode(); if (announceNewUser) { // Schedule announcement of the current user if needed. mMainHandler.sendMessageDelayed( Loading Loading @@ -2216,6 +2225,69 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mProxyManager.clearCacheLocked(); } @VisibleForTesting void updateShortcutsForCurrentNavigationMode() { synchronized (mLock) { AccessibilityUserState userState = getCurrentUserStateLocked(); if (!isUserSetupCompleted(mContext)) { return; } final boolean isInGesturalNavigation = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.NAVIGATION_MODE, -1, userState.mUserId) == NAV_BAR_MODE_GESTURAL; Set<String> gestureTargets = userState.getShortcutTargetsLocked(GESTURE); Set<String> softwareTargets = userState.getShortcutTargetsLocked(SOFTWARE); int buttonMode = ShortcutUtils.getButtonMode(mContext, userState.mUserId); if (android.provider.Flags.a11yStandaloneGestureEnabled()) { if (isInGesturalNavigation) { if (buttonMode == ACCESSIBILITY_BUTTON_MODE_GESTURE) { // GESTURE button mode indicates migrating from old version // User was using gesture, so move all targets into gesture gestureTargets.addAll(softwareTargets); softwareTargets.clear(); } buttonMode = ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; } else { // Only change the current button mode if there are gesture targets // (indicating the user came from gesture mode or is migrating) if (!gestureTargets.isEmpty()) { buttonMode = softwareTargets.isEmpty() ? ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR : ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; softwareTargets.addAll(gestureTargets); gestureTargets.clear(); } } } else { if (!gestureTargets.isEmpty()) { // Adjust button mode before clearing out gesture targets if (!softwareTargets.isEmpty()) { buttonMode = ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; } else if (isInGesturalNavigation) { buttonMode = ACCESSIBILITY_BUTTON_MODE_GESTURE; } else { buttonMode = ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; } softwareTargets.addAll(gestureTargets); gestureTargets.clear(); } else if (buttonMode != ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) { buttonMode = isInGesturalNavigation ? ACCESSIBILITY_BUTTON_MODE_GESTURE : ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; } } updateShortcutTargetSets(userState, Set.of( Pair.create(gestureTargets, GESTURE), Pair.create(softwareTargets, SOFTWARE) )); ShortcutUtils.setButtonMode(mContext, buttonMode, userState.mUserId); } } private void notifyMagnificationChangedLocked(int displayId, @NonNull Region region, @NonNull MagnificationConfig config) { final AccessibilityUserState state = getCurrentUserStateLocked(); Loading Loading @@ -3646,6 +3718,23 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub scheduleNotifyClientsOfServicesStateChangeLocked(userState); } private void updateShortcutTargetSets(AccessibilityUserState userState, Set<Pair<Set<String>, Integer>> targetSets) { boolean somethingChanged = false; for (Pair<Set<String>, Integer> pair : targetSets) { Set<String> targets = pair.first; int type = pair.second; if (userState.updateShortcutTargetsLocked(targets, type)) { somethingChanged = true; persistColonDelimitedSetToSettingLocked(ShortcutUtils.convertToKey(type), userState.mUserId, targets, str -> str); } } if (somethingChanged) { scheduleNotifyClientsOfServicesStateChangeLocked(userState); } } /** * 1) Check if the service assigned to accessibility button target sdk version > Q. * If it isn't, remove it from the list and associated setting. Loading Loading @@ -5505,6 +5594,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private final Uri mMouseKeysUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_MOUSE_KEYS_ENABLED); private final Uri mNavigationModeUri = Settings.Secure.getUriFor( Settings.Secure.NAVIGATION_MODE); private final Uri mUserSetupCompleteUri = Settings.Secure.getUriFor( Settings.Secure.USER_SETUP_COMPLETE); public AccessibilityContentObserver(Handler handler) { super(handler); } Loading Loading @@ -5555,6 +5650,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mAlwaysOnMagnificationUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mMouseKeysUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mNavigationModeUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mUserSetupCompleteUri, false, this, UserHandle.USER_ALL); } @Override Loading Loading @@ -5639,6 +5738,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (readMouseKeysEnabledLocked(userState)) { onUserStateChangedLocked(userState); } } else if (mNavigationModeUri.equals(uri) || mUserSetupCompleteUri.equals(uri)) { updateShortcutsForCurrentNavigationMode(); } } } Loading
services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java +4 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ import android.view.accessibility.IAccessibilityManagerClient; import com.android.internal.R; import com.android.internal.accessibility.AccessibilityShortcutController; import com.android.internal.accessibility.util.ShortcutUtils; import java.io.FileDescriptor; import java.io.PrintWriter; Loading Loading @@ -579,6 +580,9 @@ class AccessibilityUserState { .append(String.valueOf(mAlwaysOnMagnificationEnabled)); pw.append("}"); pw.println(); pw.append(" button mode: "); pw.append(String.valueOf(ShortcutUtils.getButtonMode(mContext, mUserId))); pw.println(); dumpShortcutTargets(pw, HARDWARE, "shortcut key"); dumpShortcutTargets(pw, SOFTWARE, "button"); pw.append(" button target:{").append(mTargetAssignedToAccessibilityButton); Loading
services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java +215 −49 File changed.Preview size limit exceeded, changes collapsed. Show changes