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:
committed by
Android (Google) Code Review
commit
3f37ab5d9c
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user