Loading core/java/android/view/accessibility/AccessibilityManager.java +11 −0 Original line number Diff line number Diff line Loading @@ -230,6 +230,17 @@ public final class AccessibilityManager { */ public static final int FLAG_CONTENT_CONTROLS = 4; /** * {@link ComponentName} for the Accessibility Menu {@link AccessibilityService} as provided * inside the system build, used for automatic migration to this version of the service. * @hide */ public static final ComponentName ACCESSIBILITY_MENU_IN_SYSTEM = new ComponentName("com.android.systemui.accessibility.accessibilitymenu", "com.android.systemui.accessibility.accessibilitymenu" + ".AccessibilityMenuService"); @UnsupportedAppUsage static final Object sInstanceSync = new Object(); Loading services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +96 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAG import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED; import static android.provider.Settings.Secure.CONTRAST_LEVEL; import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON; import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_MENU_IN_SYSTEM; import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY; import static android.view.accessibility.AccessibilityManager.CONTRAST_DEFAULT_VALUE; import static android.view.accessibility.AccessibilityManager.CONTRAST_NOT_SET; Loading Loading @@ -170,6 +171,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; Loading Loading @@ -215,6 +217,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private static final String SET_PIP_ACTION_REPLACEMENT = "setPictureInPictureActionReplacingConnection"; @VisibleForTesting static final String MENU_SERVICE_RELATIVE_CLASS_NAME = ".AccessibilityMenuService"; private static final char COMPONENT_NAME_SEPARATOR = ':'; private static final int OWN_PROCESS_ID = android.os.Process.myPid(); Loading Loading @@ -823,6 +828,95 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub Context.RECEIVER_EXPORTED); } /** * Migrates the Accessibility Menu to the version provided by the system build, * if necessary based on presence of the service on the device. */ @VisibleForTesting void migrateAccessibilityMenuIfNecessaryLocked(AccessibilityUserState userState) { final Set<ComponentName> menuComponentNames = findA11yMenuComponentNamesLocked(); final ComponentName menuOutsideSystem = getA11yMenuOutsideSystem(menuComponentNames); final boolean shouldMigrateToMenuInSystem = menuComponentNames.size() == 2 && menuComponentNames.contains(ACCESSIBILITY_MENU_IN_SYSTEM) && menuOutsideSystem != null; if (!shouldMigrateToMenuInSystem) { if (menuComponentNames.size() == 1) { // If only one Menu package exists then reset its component to the default state. mPackageManager.setComponentEnabledSetting( menuComponentNames.stream().findFirst().get(), PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, PackageManager.DONT_KILL_APP); } return; } // Hide Menu-outside-system so that it does not appear in Settings. mPackageManager.setComponentEnabledSetting( menuOutsideSystem, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); // Migrate the accessibility shortcuts. migrateA11yMenuInSettingLocked(userState, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, menuOutsideSystem); migrateA11yMenuInSettingLocked(userState, Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, menuOutsideSystem); migrateA11yMenuInSettingLocked(userState, Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, menuOutsideSystem); // If Menu-outside-system is currently enabled by the user then automatically // disable it and enable Menu-in-system. migrateA11yMenuInSettingLocked(userState, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, menuOutsideSystem); } /** * Returns all {@link ComponentName}s whose class name ends in {@link * #MENU_SERVICE_RELATIVE_CLASS_NAME}. **/ private Set<ComponentName> findA11yMenuComponentNamesLocked() { Set<ComponentName> result = new ArraySet<>(); final var flags = PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); for (ResolveInfo resolveInfo : mPackageManager.queryIntentServicesAsUser( new Intent(AccessibilityService.SERVICE_INTERFACE), flags, mCurrentUserId)) { final ComponentName componentName = resolveInfo.serviceInfo.getComponentName(); if (componentName.getClassName().endsWith(MENU_SERVICE_RELATIVE_CLASS_NAME)) { result.add(componentName); } } return result; } /** * Returns the first {@link ComponentName} in the provided set that is not equal to {@link * AccessibilityManager#ACCESSIBILITY_MENU_IN_SYSTEM}. */ private static ComponentName getA11yMenuOutsideSystem(Set<ComponentName> menuComponentNames) { Optional<ComponentName> menuOutsideSystem = menuComponentNames.stream().filter( name -> !name.equals(ACCESSIBILITY_MENU_IN_SYSTEM)).findFirst(); if (menuOutsideSystem.isEmpty()) { return null; } return menuOutsideSystem.get(); } /** * Replaces <code>toRemove</code> with {@link AccessibilityManager#ACCESSIBILITY_MENU_IN_SYSTEM} * in the requested setting, if present already. */ private void migrateA11yMenuInSettingLocked(AccessibilityUserState userState, String setting, ComponentName toRemove) { mTempComponentNameSet.clear(); readComponentNamesFromSettingLocked(setting, userState.mUserId, mTempComponentNameSet); if (mTempComponentNameSet.contains(toRemove)) { mTempComponentNameSet.remove(toRemove); mTempComponentNameSet.add(ACCESSIBILITY_MENU_IN_SYSTEM); persistComponentNamesToSettingLocked(setting, mTempComponentNameSet, userState.mUserId); } } // Called only during settings restore; currently supports only the owner user // TODO: b/22388012 private void restoreLegacyDisplayMagnificationNavBarIfNeededLocked(String newSetting, Loading Loading @@ -1592,6 +1686,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mCurrentUserId = userId; AccessibilityUserState userState = getCurrentUserStateLocked(); migrateAccessibilityMenuIfNecessaryLocked(userState); readConfigurationForUserStateLocked(userState); mSecurityPolicy.onSwitchUserLocked(mCurrentUserId, userState.mEnabledServices); // Even if reading did not yield change, we have to update Loading services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java +114 −0 Original line number Diff line number Diff line Loading @@ -16,13 +16,19 @@ package com.android.server.accessibility; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_NONE; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW; import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE; import static android.provider.Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES; import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_MENU_IN_SYSTEM; import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; import static com.android.server.accessibility.AccessibilityManagerService.MENU_SERVICE_RELATIVE_CLASS_NAME; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -93,6 +99,7 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.List; /** * APCT tests for {@link AccessibilityManagerService}. Loading Loading @@ -514,6 +521,113 @@ public class AccessibilityManagerServiceTest { ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString()); } @Test public void testMigrateA11yMenu_ResetSingularComponentToDefaultState() { final ComponentName componentName = ComponentName.createRelative("external", MENU_SERVICE_RELATIVE_CLASS_NAME); when(mMockPackageManager.queryIntentServicesAsUser(any(), any(), eq(mA11yms.getCurrentUserIdLocked()))).thenReturn( List.of(createResolveInfo(componentName))); mA11yms.migrateAccessibilityMenuIfNecessaryLocked(mA11yms.getCurrentUserState()); verify(mMockPackageManager).setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, PackageManager.DONT_KILL_APP); } @Test public void testMigrateA11yMenu_DoNothing_WhenNoMenuComponents() { when(mMockPackageManager.queryIntentServicesAsUser(any(), any(), eq(mA11yms.getCurrentUserIdLocked()))).thenReturn(List.of()); mA11yms.migrateAccessibilityMenuIfNecessaryLocked(mA11yms.getCurrentUserState()); verify(mMockPackageManager, never()).setComponentEnabledSetting(any(), anyInt(), anyInt()); } @Test public void testMigrateA11yMenu_DoNothing_WhenTooManyMenuComponents() { when(mMockPackageManager.queryIntentServicesAsUser(any(), any(), eq(mA11yms.getCurrentUserIdLocked()))).thenReturn(List.of( createResolveInfo(ComponentName.createRelative("external1", MENU_SERVICE_RELATIVE_CLASS_NAME)), createResolveInfo(ComponentName.createRelative("external2", MENU_SERVICE_RELATIVE_CLASS_NAME)), createResolveInfo(ComponentName.createRelative("external3", MENU_SERVICE_RELATIVE_CLASS_NAME)))); mA11yms.migrateAccessibilityMenuIfNecessaryLocked(mA11yms.getCurrentUserState()); verify(mMockPackageManager, never()).setComponentEnabledSetting(any(), anyInt(), anyInt()); } @Test public void testMigrateA11yMenu_DoNothing_WhenNoMenuInSystem() { when(mMockPackageManager.queryIntentServicesAsUser(any(), any(), eq(mA11yms.getCurrentUserIdLocked()))).thenReturn(List.of( createResolveInfo(ComponentName.createRelative("external1", MENU_SERVICE_RELATIVE_CLASS_NAME)), createResolveInfo(ComponentName.createRelative("external2", MENU_SERVICE_RELATIVE_CLASS_NAME)))); mA11yms.migrateAccessibilityMenuIfNecessaryLocked(mA11yms.getCurrentUserState()); verify(mMockPackageManager, never()).setComponentEnabledSetting(any(), anyInt(), anyInt()); } @Test public void testMigrateA11yMenu_PerformsMigration() { final ComponentName menuOutsideSystem = ComponentName.createRelative("external", MENU_SERVICE_RELATIVE_CLASS_NAME); final String[] migratedSettings = { ACCESSIBILITY_BUTTON_TARGETS, ACCESSIBILITY_BUTTON_TARGET_COMPONENT, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, ENABLED_ACCESSIBILITY_SERVICES }; // Start the user with Menu-outside-system enabled, for (String setting : migratedSettings) { Settings.Secure.putStringForUser( mTestableContext.getContentResolver(), setting, menuOutsideSystem.flattenToShortString(), mA11yms.getCurrentUserIdLocked()); } // and both Menu versions present. when(mMockPackageManager.queryIntentServicesAsUser(any(), any(), eq(mA11yms.getCurrentUserIdLocked()))).thenReturn(List.of( createResolveInfo(menuOutsideSystem), createResolveInfo(ACCESSIBILITY_MENU_IN_SYSTEM))); mA11yms.migrateAccessibilityMenuIfNecessaryLocked(mA11yms.getCurrentUserState()); // Menu-outside-system should be disabled, verify(mMockPackageManager).setComponentEnabledSetting(menuOutsideSystem, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); // and all settings should migrated to Menu-in-system. for (String setting : migratedSettings) { ComponentName componentName = ComponentName.unflattenFromString( Settings.Secure.getStringForUser( mTestableContext.getContentResolver(), setting, mA11yms.getCurrentUserIdLocked())); assertThat(componentName).isEqualTo(ACCESSIBILITY_MENU_IN_SYSTEM); } } private static ResolveInfo createResolveInfo(ComponentName componentName) { ResolveInfo resolveInfo = new ResolveInfo(); resolveInfo.serviceInfo = new ServiceInfo(); resolveInfo.serviceInfo.packageName = componentName.getPackageName(); resolveInfo.serviceInfo.name = componentName.getClassName(); return resolveInfo; } private void mockManageAccessibilityGranted(TestableContext context) { context.getTestablePermissions().setPermission(Manifest.permission.MANAGE_ACCESSIBILITY, PackageManager.PERMISSION_GRANTED); Loading Loading
core/java/android/view/accessibility/AccessibilityManager.java +11 −0 Original line number Diff line number Diff line Loading @@ -230,6 +230,17 @@ public final class AccessibilityManager { */ public static final int FLAG_CONTENT_CONTROLS = 4; /** * {@link ComponentName} for the Accessibility Menu {@link AccessibilityService} as provided * inside the system build, used for automatic migration to this version of the service. * @hide */ public static final ComponentName ACCESSIBILITY_MENU_IN_SYSTEM = new ComponentName("com.android.systemui.accessibility.accessibilitymenu", "com.android.systemui.accessibility.accessibilitymenu" + ".AccessibilityMenuService"); @UnsupportedAppUsage static final Object sInstanceSync = new Object(); Loading
services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +96 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAG import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED; import static android.provider.Settings.Secure.CONTRAST_LEVEL; import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON; import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_MENU_IN_SYSTEM; import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY; import static android.view.accessibility.AccessibilityManager.CONTRAST_DEFAULT_VALUE; import static android.view.accessibility.AccessibilityManager.CONTRAST_NOT_SET; Loading Loading @@ -170,6 +171,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; Loading Loading @@ -215,6 +217,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private static final String SET_PIP_ACTION_REPLACEMENT = "setPictureInPictureActionReplacingConnection"; @VisibleForTesting static final String MENU_SERVICE_RELATIVE_CLASS_NAME = ".AccessibilityMenuService"; private static final char COMPONENT_NAME_SEPARATOR = ':'; private static final int OWN_PROCESS_ID = android.os.Process.myPid(); Loading Loading @@ -823,6 +828,95 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub Context.RECEIVER_EXPORTED); } /** * Migrates the Accessibility Menu to the version provided by the system build, * if necessary based on presence of the service on the device. */ @VisibleForTesting void migrateAccessibilityMenuIfNecessaryLocked(AccessibilityUserState userState) { final Set<ComponentName> menuComponentNames = findA11yMenuComponentNamesLocked(); final ComponentName menuOutsideSystem = getA11yMenuOutsideSystem(menuComponentNames); final boolean shouldMigrateToMenuInSystem = menuComponentNames.size() == 2 && menuComponentNames.contains(ACCESSIBILITY_MENU_IN_SYSTEM) && menuOutsideSystem != null; if (!shouldMigrateToMenuInSystem) { if (menuComponentNames.size() == 1) { // If only one Menu package exists then reset its component to the default state. mPackageManager.setComponentEnabledSetting( menuComponentNames.stream().findFirst().get(), PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, PackageManager.DONT_KILL_APP); } return; } // Hide Menu-outside-system so that it does not appear in Settings. mPackageManager.setComponentEnabledSetting( menuOutsideSystem, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); // Migrate the accessibility shortcuts. migrateA11yMenuInSettingLocked(userState, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, menuOutsideSystem); migrateA11yMenuInSettingLocked(userState, Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, menuOutsideSystem); migrateA11yMenuInSettingLocked(userState, Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, menuOutsideSystem); // If Menu-outside-system is currently enabled by the user then automatically // disable it and enable Menu-in-system. migrateA11yMenuInSettingLocked(userState, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, menuOutsideSystem); } /** * Returns all {@link ComponentName}s whose class name ends in {@link * #MENU_SERVICE_RELATIVE_CLASS_NAME}. **/ private Set<ComponentName> findA11yMenuComponentNamesLocked() { Set<ComponentName> result = new ArraySet<>(); final var flags = PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); for (ResolveInfo resolveInfo : mPackageManager.queryIntentServicesAsUser( new Intent(AccessibilityService.SERVICE_INTERFACE), flags, mCurrentUserId)) { final ComponentName componentName = resolveInfo.serviceInfo.getComponentName(); if (componentName.getClassName().endsWith(MENU_SERVICE_RELATIVE_CLASS_NAME)) { result.add(componentName); } } return result; } /** * Returns the first {@link ComponentName} in the provided set that is not equal to {@link * AccessibilityManager#ACCESSIBILITY_MENU_IN_SYSTEM}. */ private static ComponentName getA11yMenuOutsideSystem(Set<ComponentName> menuComponentNames) { Optional<ComponentName> menuOutsideSystem = menuComponentNames.stream().filter( name -> !name.equals(ACCESSIBILITY_MENU_IN_SYSTEM)).findFirst(); if (menuOutsideSystem.isEmpty()) { return null; } return menuOutsideSystem.get(); } /** * Replaces <code>toRemove</code> with {@link AccessibilityManager#ACCESSIBILITY_MENU_IN_SYSTEM} * in the requested setting, if present already. */ private void migrateA11yMenuInSettingLocked(AccessibilityUserState userState, String setting, ComponentName toRemove) { mTempComponentNameSet.clear(); readComponentNamesFromSettingLocked(setting, userState.mUserId, mTempComponentNameSet); if (mTempComponentNameSet.contains(toRemove)) { mTempComponentNameSet.remove(toRemove); mTempComponentNameSet.add(ACCESSIBILITY_MENU_IN_SYSTEM); persistComponentNamesToSettingLocked(setting, mTempComponentNameSet, userState.mUserId); } } // Called only during settings restore; currently supports only the owner user // TODO: b/22388012 private void restoreLegacyDisplayMagnificationNavBarIfNeededLocked(String newSetting, Loading Loading @@ -1592,6 +1686,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mCurrentUserId = userId; AccessibilityUserState userState = getCurrentUserStateLocked(); migrateAccessibilityMenuIfNecessaryLocked(userState); readConfigurationForUserStateLocked(userState); mSecurityPolicy.onSwitchUserLocked(mCurrentUserId, userState.mEnabledServices); // Even if reading did not yield change, we have to update Loading
services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java +114 −0 Original line number Diff line number Diff line Loading @@ -16,13 +16,19 @@ package com.android.server.accessibility; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_NONE; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW; import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE; import static android.provider.Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES; import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_MENU_IN_SYSTEM; import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; import static com.android.server.accessibility.AccessibilityManagerService.MENU_SERVICE_RELATIVE_CLASS_NAME; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -93,6 +99,7 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.List; /** * APCT tests for {@link AccessibilityManagerService}. Loading Loading @@ -514,6 +521,113 @@ public class AccessibilityManagerServiceTest { ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString()); } @Test public void testMigrateA11yMenu_ResetSingularComponentToDefaultState() { final ComponentName componentName = ComponentName.createRelative("external", MENU_SERVICE_RELATIVE_CLASS_NAME); when(mMockPackageManager.queryIntentServicesAsUser(any(), any(), eq(mA11yms.getCurrentUserIdLocked()))).thenReturn( List.of(createResolveInfo(componentName))); mA11yms.migrateAccessibilityMenuIfNecessaryLocked(mA11yms.getCurrentUserState()); verify(mMockPackageManager).setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, PackageManager.DONT_KILL_APP); } @Test public void testMigrateA11yMenu_DoNothing_WhenNoMenuComponents() { when(mMockPackageManager.queryIntentServicesAsUser(any(), any(), eq(mA11yms.getCurrentUserIdLocked()))).thenReturn(List.of()); mA11yms.migrateAccessibilityMenuIfNecessaryLocked(mA11yms.getCurrentUserState()); verify(mMockPackageManager, never()).setComponentEnabledSetting(any(), anyInt(), anyInt()); } @Test public void testMigrateA11yMenu_DoNothing_WhenTooManyMenuComponents() { when(mMockPackageManager.queryIntentServicesAsUser(any(), any(), eq(mA11yms.getCurrentUserIdLocked()))).thenReturn(List.of( createResolveInfo(ComponentName.createRelative("external1", MENU_SERVICE_RELATIVE_CLASS_NAME)), createResolveInfo(ComponentName.createRelative("external2", MENU_SERVICE_RELATIVE_CLASS_NAME)), createResolveInfo(ComponentName.createRelative("external3", MENU_SERVICE_RELATIVE_CLASS_NAME)))); mA11yms.migrateAccessibilityMenuIfNecessaryLocked(mA11yms.getCurrentUserState()); verify(mMockPackageManager, never()).setComponentEnabledSetting(any(), anyInt(), anyInt()); } @Test public void testMigrateA11yMenu_DoNothing_WhenNoMenuInSystem() { when(mMockPackageManager.queryIntentServicesAsUser(any(), any(), eq(mA11yms.getCurrentUserIdLocked()))).thenReturn(List.of( createResolveInfo(ComponentName.createRelative("external1", MENU_SERVICE_RELATIVE_CLASS_NAME)), createResolveInfo(ComponentName.createRelative("external2", MENU_SERVICE_RELATIVE_CLASS_NAME)))); mA11yms.migrateAccessibilityMenuIfNecessaryLocked(mA11yms.getCurrentUserState()); verify(mMockPackageManager, never()).setComponentEnabledSetting(any(), anyInt(), anyInt()); } @Test public void testMigrateA11yMenu_PerformsMigration() { final ComponentName menuOutsideSystem = ComponentName.createRelative("external", MENU_SERVICE_RELATIVE_CLASS_NAME); final String[] migratedSettings = { ACCESSIBILITY_BUTTON_TARGETS, ACCESSIBILITY_BUTTON_TARGET_COMPONENT, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, ENABLED_ACCESSIBILITY_SERVICES }; // Start the user with Menu-outside-system enabled, for (String setting : migratedSettings) { Settings.Secure.putStringForUser( mTestableContext.getContentResolver(), setting, menuOutsideSystem.flattenToShortString(), mA11yms.getCurrentUserIdLocked()); } // and both Menu versions present. when(mMockPackageManager.queryIntentServicesAsUser(any(), any(), eq(mA11yms.getCurrentUserIdLocked()))).thenReturn(List.of( createResolveInfo(menuOutsideSystem), createResolveInfo(ACCESSIBILITY_MENU_IN_SYSTEM))); mA11yms.migrateAccessibilityMenuIfNecessaryLocked(mA11yms.getCurrentUserState()); // Menu-outside-system should be disabled, verify(mMockPackageManager).setComponentEnabledSetting(menuOutsideSystem, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); // and all settings should migrated to Menu-in-system. for (String setting : migratedSettings) { ComponentName componentName = ComponentName.unflattenFromString( Settings.Secure.getStringForUser( mTestableContext.getContentResolver(), setting, mA11yms.getCurrentUserIdLocked())); assertThat(componentName).isEqualTo(ACCESSIBILITY_MENU_IN_SYSTEM); } } private static ResolveInfo createResolveInfo(ComponentName componentName) { ResolveInfo resolveInfo = new ResolveInfo(); resolveInfo.serviceInfo = new ServiceInfo(); resolveInfo.serviceInfo.packageName = componentName.getPackageName(); resolveInfo.serviceInfo.name = componentName.getClassName(); return resolveInfo; } private void mockManageAccessibilityGranted(TestableContext context) { context.getTestablePermissions().setPermission(Manifest.permission.MANAGE_ACCESSIBILITY, PackageManager.PERMISSION_GRANTED); Loading