Merge changes from topic "menu-migrate-settings-provider"

* changes:
  Migrates to the new component name for A11yMenu in SettingsProvider.
  Extracts out A11yMenu Settings migration logic to AccessibilityUtils.
This commit is contained in:
Daniel Norman
2023-02-09 23:05:10 +00:00
committed by Android (Google) Code Review
6 changed files with 230 additions and 224 deletions

View File

@@ -255,17 +255,6 @@ 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();

View File

@@ -19,11 +19,16 @@ package com.android.internal.accessibility.util;
import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR;
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.os.UserHandle;
import android.provider.Settings;
@@ -33,6 +38,8 @@ import android.text.TextUtils;
import android.util.ArraySet;
import android.view.accessibility.AccessibilityManager;
import com.android.internal.annotations.VisibleForTesting;
import libcore.util.EmptyArray;
import java.lang.annotation.Retention;
@@ -40,6 +47,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
/**
@@ -66,6 +74,19 @@ public final class AccessibilityUtils {
/** Specifies some parcelable spans has been changed. */
public static final int PARCELABLE_SPAN = 2;
@VisibleForTesting
public static final String MENU_SERVICE_RELATIVE_CLASS_NAME = ".AccessibilityMenuService";
/**
* {@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"
+ MENU_SERVICE_RELATIVE_CLASS_NAME);
/**
* Returns the set of enabled accessibility services for userId. If there are no
* services, it returns the unmodifiable {@link Collections#emptySet()}.
@@ -244,4 +265,54 @@ public final class AccessibilityUtils {
}
return true;
}
/**
* Finds the {@link ComponentName} of the AccessibilityMenu accessibility service that the
* device should be migrated off. Devices using this service should be migrated to
* {@link #ACCESSIBILITY_MENU_IN_SYSTEM}.
*
* <p>
* Requirements:
* <li>There are exactly two installed accessibility service components with class name
* {@link #MENU_SERVICE_RELATIVE_CLASS_NAME}.</li>
* <li>Exactly one of these components is equal to {@link #ACCESSIBILITY_MENU_IN_SYSTEM}.</li>
* </p>
*
* @return The {@link ComponentName} of the service that is not {@link
* #ACCESSIBILITY_MENU_IN_SYSTEM},
* or <code>null</code> if the above requirements are not met.
*/
@Nullable
public static ComponentName getAccessibilityMenuComponentToMigrate(
PackageManager packageManager, int userId) {
final Set<ComponentName> menuComponentNames = findA11yMenuComponentNames(packageManager,
userId);
Optional<ComponentName> menuOutsideSystem = menuComponentNames.stream().filter(
name -> !name.equals(ACCESSIBILITY_MENU_IN_SYSTEM)).findFirst();
final boolean shouldMigrateToMenuInSystem = menuComponentNames.size() == 2
&& menuComponentNames.contains(ACCESSIBILITY_MENU_IN_SYSTEM)
&& menuOutsideSystem.isPresent();
return shouldMigrateToMenuInSystem ? menuOutsideSystem.get() : null;
}
/**
* Returns all {@link ComponentName}s whose class name ends in {@link
* #MENU_SERVICE_RELATIVE_CLASS_NAME}.
**/
private static Set<ComponentName> findA11yMenuComponentNames(
PackageManager packageManager, int userId) {
Set<ComponentName> result = new ArraySet<>();
final PackageManager.ResolveInfoFlags flags = PackageManager.ResolveInfoFlags.of(
PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
for (ResolveInfo resolveInfo : packageManager.queryIntentServicesAsUser(
new Intent(AccessibilityService.SERVICE_INTERFACE), flags, userId)) {
final ComponentName componentName = resolveInfo.serviceInfo.getComponentName();
if (componentName.getClassName().endsWith(MENU_SERVICE_RELATIVE_CLASS_NAME)) {
result.add(componentName);
}
}
return result;
}
}

View File

@@ -16,8 +16,19 @@
package com.android.internal.accessibility;
import static junit.framework.Assert.assertEquals;
import static com.android.internal.accessibility.util.AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM;
import static com.android.internal.accessibility.util.AccessibilityUtils.MENU_SERVICE_RELATIVE_CLASS_NAME;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.text.ParcelableSpan;
import android.text.SpannableString;
import android.text.style.LocaleSpan;
@@ -26,9 +37,13 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.accessibility.util.AccessibilityUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.List;
import java.util.Locale;
/**
@@ -36,6 +51,15 @@ import java.util.Locale;
*/
@RunWith(AndroidJUnit4.class)
public class AccessibilityUtilsTest {
private static final int USER_ID = 123;
@Mock
private PackageManager mMockPackageManager;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void textOrSpanChanged_stringChange_returnTextChange() {
final CharSequence beforeText = "a";
@@ -44,7 +68,7 @@ public class AccessibilityUtilsTest {
@AccessibilityUtils.A11yTextChangeType int type = AccessibilityUtils.textOrSpanChanged(
beforeText, afterText);
assertEquals(AccessibilityUtils.TEXT, type);
assertThat(type).isEqualTo(AccessibilityUtils.TEXT);
}
@Test
@@ -55,7 +79,7 @@ public class AccessibilityUtilsTest {
@AccessibilityUtils.A11yTextChangeType int type = AccessibilityUtils.textOrSpanChanged(
beforeText, afterText);
assertEquals(AccessibilityUtils.NONE, type);
assertThat(type).isEqualTo(AccessibilityUtils.NONE);
}
@Test
@@ -68,7 +92,7 @@ public class AccessibilityUtilsTest {
@AccessibilityUtils.A11yTextChangeType int type = AccessibilityUtils.textOrSpanChanged(
beforeText, afterText);
assertEquals(AccessibilityUtils.NONE, type);
assertThat(type).isEqualTo(AccessibilityUtils.NONE);
}
@Test
@@ -81,7 +105,7 @@ public class AccessibilityUtilsTest {
@AccessibilityUtils.A11yTextChangeType int type = AccessibilityUtils.textOrSpanChanged(
beforeText, afterText);
assertEquals(AccessibilityUtils.PARCELABLE_SPAN, type);
assertThat(type).isEqualTo(AccessibilityUtils.PARCELABLE_SPAN);
}
@Test
@@ -96,7 +120,7 @@ public class AccessibilityUtilsTest {
@AccessibilityUtils.A11yTextChangeType int type = AccessibilityUtils.textOrSpanChanged(
beforeText, afterText);
assertEquals(AccessibilityUtils.PARCELABLE_SPAN, type);
assertThat(type).isEqualTo(AccessibilityUtils.PARCELABLE_SPAN);
}
@Test
@@ -110,7 +134,7 @@ public class AccessibilityUtilsTest {
@AccessibilityUtils.A11yTextChangeType int type = AccessibilityUtils.textOrSpanChanged(
beforeText, afterText);
assertEquals(AccessibilityUtils.NONE, type);
assertThat(type).isEqualTo(AccessibilityUtils.NONE);
}
@Test
@@ -124,6 +148,72 @@ public class AccessibilityUtilsTest {
@AccessibilityUtils.A11yTextChangeType int type = AccessibilityUtils.textOrSpanChanged(
beforeText, afterText);
assertEquals(AccessibilityUtils.PARCELABLE_SPAN, type);
assertThat(type).isEqualTo(AccessibilityUtils.PARCELABLE_SPAN);
}
@Test
public void getAccessibilityMenuComponentToMigrate_isNull_whenNoMenuComponents() {
when(mMockPackageManager.queryIntentServicesAsUser(any(), any(),
eq(USER_ID))).thenReturn(List.of());
final ComponentName result = AccessibilityUtils.getAccessibilityMenuComponentToMigrate(
mMockPackageManager, USER_ID);
assertThat(result).isNull();
}
@Test
public void getAccessibilityMenuComponentToMigrate_isNull_whenTooManyMenuComponents() {
when(mMockPackageManager.queryIntentServicesAsUser(any(), any(),
eq(USER_ID))).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))));
final ComponentName result = AccessibilityUtils.getAccessibilityMenuComponentToMigrate(
mMockPackageManager, USER_ID);
assertThat(result).isNull();
}
@Test
public void getAccessibilityMenuComponentToMigrate_isNull_whenMenuInSystemNotFound() {
when(mMockPackageManager.queryIntentServicesAsUser(any(), any(),
eq(USER_ID))).thenReturn(List.of(
createResolveInfo(ComponentName.createRelative("external1",
MENU_SERVICE_RELATIVE_CLASS_NAME)),
createResolveInfo(ComponentName.createRelative("external2",
MENU_SERVICE_RELATIVE_CLASS_NAME))));
final ComponentName result = AccessibilityUtils.getAccessibilityMenuComponentToMigrate(
mMockPackageManager, USER_ID);
assertThat(result).isNull();
}
@Test
public void getAccessibilityMenuComponentToMigrate_returnsMenuOutsideSystem() {
ComponentName menuOutsideSystem = ComponentName.createRelative("external1",
MENU_SERVICE_RELATIVE_CLASS_NAME);
when(mMockPackageManager.queryIntentServicesAsUser(any(), any(),
eq(USER_ID))).thenReturn(List.of(
createResolveInfo(menuOutsideSystem),
createResolveInfo(ACCESSIBILITY_MENU_IN_SYSTEM)));
final ComponentName result = AccessibilityUtils.getAccessibilityMenuComponentToMigrate(
mMockPackageManager, USER_ID);
assertThat(result).isEqualTo(menuOutsideSystem);
}
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;
}
}

View File

@@ -33,6 +33,7 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import static com.android.internal.accessibility.util.AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM;
import static com.android.providers.settings.SettingsState.FALLBACK_FILE_SUFFIX;
import android.Manifest;
@@ -107,6 +108,7 @@ import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.accessibility.util.AccessibilityUtils;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
@@ -3712,7 +3714,7 @@ public class SettingsProvider extends ContentProvider {
}
private final class UpgradeController {
private static final int SETTINGS_VERSION = 213;
private static final int SETTINGS_VERSION = 214;
private final int mUserId;
@@ -5646,6 +5648,27 @@ public class SettingsProvider extends ContentProvider {
currentVersion = 213;
}
if (currentVersion == 213) {
final ComponentName accessibilityMenuToMigrate =
AccessibilityUtils.getAccessibilityMenuComponentToMigrate(
getContext().getPackageManager(), userId);
if (accessibilityMenuToMigrate != null) {
final SettingsState secureSettings = getSecureSettingsLocked(userId);
final String toRemove = accessibilityMenuToMigrate.flattenToString();
final String toAdd = ACCESSIBILITY_MENU_IN_SYSTEM.flattenToString();
// Migrate the accessibility shortcuts and enabled state.
migrateColonDelimitedStringSettingLocked(secureSettings,
Secure.ACCESSIBILITY_BUTTON_TARGETS, toRemove, toAdd);
migrateColonDelimitedStringSettingLocked(secureSettings,
Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, toRemove, toAdd);
migrateColonDelimitedStringSettingLocked(secureSettings,
Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, toRemove, toAdd);
migrateColonDelimitedStringSettingLocked(secureSettings,
Secure.ENABLED_ACCESSIBILITY_SERVICES, toRemove, toAdd);
}
currentVersion = 214;
}
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
@@ -5867,6 +5890,22 @@ public class SettingsProvider extends ContentProvider {
return items;
}
@GuardedBy("mLock")
private void migrateColonDelimitedStringSettingLocked(SettingsState settingsState,
String setting, String toRemove, String toAdd) {
final Set<String> componentNames = transformColonDelimitedStringToSet(
settingsState.getSettingLocked(setting).getValue());
if (componentNames != null && componentNames.contains(toRemove)) {
componentNames.remove(toRemove);
componentNames.add(toAdd);
settingsState.insertSettingLocked(
setting,
TextUtils.join(":", componentNames),
null /* tag */, false /* makeDefault */,
SettingsState.SYSTEM_PACKAGE_NAME);
}
}
private boolean isAccessibilityButtonInNavigationBarOn(SettingsState secureSettings) {
return hasValueInA11yButtonTargets(secureSettings) && !isGestureNavigateEnabled();
}

View File

@@ -28,7 +28,6 @@ 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;
@@ -138,6 +137,7 @@ import com.android.internal.accessibility.AccessibilityShortcutController.Framew
import com.android.internal.accessibility.AccessibilityShortcutController.LaunchableFrameworkFeatureInfo;
import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity;
import com.android.internal.accessibility.dialog.AccessibilityShortcutChooserActivity;
import com.android.internal.accessibility.util.AccessibilityUtils;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
@@ -172,7 +172,6 @@ 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;
@@ -218,9 +217,6 @@ 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();
@@ -484,6 +480,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
registerBroadcastReceivers();
new AccessibilityContentObserver(mMainHandler).register(
mContext.getContentResolver());
disableAccessibilityMenuToMigrateIfNeeded();
}
@Override
@@ -855,91 +852,27 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
/**
* Migrates the Accessibility Menu to the version provided by the system build,
* if necessary based on presence of the service on the device.
* Disables the component returned by
* {@link AccessibilityUtils#getAccessibilityMenuComponentToMigrate} so that it does not appear
* in Settings or other places that query for installed accessibility services.
*
* <p>
* SettingsProvider is responsible for migrating users off of Menu-outside-system,
* which it performs in its initialization before AccessibilityManagerService is started.
* </p>
*/
@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;
private void disableAccessibilityMenuToMigrateIfNeeded() {
int userId;
synchronized (mLock) {
userId = mCurrentUserId;
}
// 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);
final ComponentName menuToMigrate =
AccessibilityUtils.getAccessibilityMenuComponentToMigrate(mPackageManager, userId);
if (menuToMigrate != null) {
mPackageManager.setComponentEnabledSetting(
menuToMigrate,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
}
@@ -1712,8 +1645,6 @@ 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

View File

@@ -16,19 +16,13 @@
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;
@@ -100,7 +94,6 @@ import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
/**
* APCT tests for {@link AccessibilityManagerService}.
@@ -558,113 +551,6 @@ 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);