Merge "Updating ACCESSIBILITY_QS_TARGETS when user moves the A11y QS tiles in the QS Panel" into main
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index e215950..614df7c 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -142,7 +142,7 @@
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW)")
void attachAccessibilityOverlayToDisplay(int displayId, in SurfaceControl surfaceControl);
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE)")
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.STATUS_BAR_SERVICE,android.Manifest.permission.MANAGE_ACCESSIBILITY})")
oneway void notifyQuickSettingsTilesChanged(int userId, in List<ComponentName> tileComponentNames);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY)")
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 4be303a..2d531e7 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1706,20 +1706,101 @@
}
@Override
- @RequiresPermission(Manifest.permission.STATUS_BAR_SERVICE)
+ @RequiresPermission(allOf = {
+ Manifest.permission.STATUS_BAR_SERVICE,
+ Manifest.permission.MANAGE_ACCESSIBILITY
+ })
public void notifyQuickSettingsTilesChanged(
- @UserIdInt int userId, List<ComponentName> tileComponentNames) {
- mSecurityPolicy.enforceCallingPermission(
+ @UserIdInt int userId, @NonNull List<ComponentName> tileComponentNames) {
+ if (!android.view.accessibility.Flags.a11yQsShortcut()) {
+ return;
+ }
+
+ mContext.enforceCallingPermission(
Manifest.permission.STATUS_BAR_SERVICE,
/* function= */ "notifyQuickSettingsTilesChanged");
+ mContext.enforceCallingPermission(
+ Manifest.permission.MANAGE_ACCESSIBILITY,
+ /* function= */ "notifyQuickSettingsTilesChanged");
- Slog.d(LOG_TAG, TextUtils.formatSimple(
- "notifyQuickSettingsTilesChanged userId: %d, tileComponentNames: %s",
- userId, tileComponentNames));
- // TODO (b/314843909): in the follow up cl
+ if (DEBUG) {
+ Slog.d(LOG_TAG, TextUtils.formatSimple(
+ "notifyQuickSettingsTilesChanged userId: %d, tileComponentNames: %s",
+ userId, tileComponentNames));
+ }
+ final Set<ComponentName> newTileComponentNames = new ArraySet<>(tileComponentNames);
+ final Set<ComponentName> addedTiles;
+ final Set<ComponentName> removedTiles;
+ final Map<ComponentName, AccessibilityServiceInfo> tileServiceToA11yServiceInfo;
+ final Map<ComponentName, ComponentName> a11yFeatureToTileService;
+
// update in-memory copy of QS_TILES in AccessibilityManager
- // update Settings.Secure.ACCESSIBILITY_QS_TARGETS and its in-memory copy
- // show full device control warning if needed (b/314850435)
+ synchronized (mLock) {
+ AccessibilityUserState userState = getUserStateLocked(userId);
+
+ tileServiceToA11yServiceInfo = userState.getTileServiceToA11yServiceInfoMapLocked();
+ a11yFeatureToTileService = userState.getA11yFeatureToTileService();
+
+ ArraySet<ComponentName> currentTiles = userState.getA11yQsTilesInQsPanel();
+ // Find newly added tiles
+ addedTiles = newTileComponentNames
+ .stream()
+ .filter(tileComponentName -> !currentTiles.contains(tileComponentName))
+ .collect(Collectors.toSet());
+ // Find newly removed tiles
+ removedTiles = currentTiles
+ .stream()
+ .filter(tileComponentName -> !newTileComponentNames.contains(tileComponentName))
+ .collect(Collectors.toSet());
+
+ if (addedTiles.isEmpty() && removedTiles.isEmpty()) {
+ return;
+ }
+
+ userState.updateA11yTilesInQsPanelLocked(newTileComponentNames);
+ }
+
+ List<String> a11yFeaturesToEnable = new ArrayList<>();
+ List<String> a11yFeaturesToRemove = new ArrayList<>();
+ // Find the framework features to configure the qs shortcut on/off
+ for (Map.Entry<ComponentName, ComponentName> frameworkFeatureWithTile :
+ ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE.entrySet()) {
+ String a11yFeature = frameworkFeatureWithTile.getKey().flattenToString();
+ ComponentName tile = frameworkFeatureWithTile.getValue();
+ if (addedTiles.contains(tile)) {
+ a11yFeaturesToEnable.add(a11yFeature);
+ } else if (removedTiles.contains(tile)) {
+ a11yFeaturesToRemove.add(a11yFeature);
+ }
+ }
+ // Find the accessibility service/activity to configure the qs shortcut on/off
+ for (Map.Entry<ComponentName, ComponentName> a11yFeatureWithTileService :
+ a11yFeatureToTileService.entrySet()) {
+ String a11yFeature = a11yFeatureWithTileService.getKey().flattenToString();
+ ComponentName tileService = a11yFeatureWithTileService.getValue();
+ if (addedTiles.contains(tileService)) {
+ AccessibilityServiceInfo serviceInfo = tileServiceToA11yServiceInfo.getOrDefault(
+ tileService, null);
+ if (serviceInfo != null && isAccessibilityServiceWarningRequired(serviceInfo)) {
+ // TODO(b/314850435): show full device control warning if needed after
+ // SysUI QS Panel can update live
+ continue;
+ }
+ a11yFeaturesToEnable.add(a11yFeature);
+ } else if (removedTiles.contains(tileService)) {
+ a11yFeaturesToRemove.add(a11yFeature);
+ }
+ }
+ // Turn on/off a11y qs shortcut for the a11y features based on the change in QS Panel
+ if (!a11yFeaturesToEnable.isEmpty()) {
+ enableShortcutForTargets(/* enable= */ true, UserShortcutType.QUICK_SETTINGS,
+ a11yFeaturesToEnable, userId);
+ }
+
+ if (!a11yFeaturesToRemove.isEmpty()) {
+ enableShortcutForTargets(/* enable= */ false, UserShortcutType.QUICK_SETTINGS,
+ a11yFeaturesToRemove, userId);
+ }
}
/**
@@ -3661,18 +3742,35 @@
/**
* Update the Settings.Secure.ACCESSIBILITY_QS_TARGETS so that it only contains valid content,
* and a side loaded service can't spoof the package name of the default service.
+ * <p>
+ * 1. Remove the target if the target is no longer installed on the device <br/>
+ * 2. Add the target if the target is enabled and the target's tile is in the QS Panel <br/>
+ * </p>
*/
private void updateAccessibilityQsTargetsLocked(AccessibilityUserState userState) {
- final Set<String> targets =
- userState.getShortcutTargetsLocked(UserShortcutType.QUICK_SETTINGS);
- final int lastSize = targets.size();
- if (lastSize == 0) {
+ if (!android.view.accessibility.Flags.a11yQsShortcut()) {
return;
}
+ final Set<String> targets =
+ userState.getShortcutTargetsLocked(UserShortcutType.QUICK_SETTINGS);
+
// Removes the targets that are no longer installed on the device.
boolean somethingChanged = targets.removeIf(
name -> !userState.isShortcutTargetInstalledLocked(name));
+ // Add the target if the a11y service is enabled and the tile exist in QS panel
+ Set<ComponentName> enabledServices = userState.getEnabledServicesLocked();
+ Map<ComponentName, ComponentName> a11yFeatureToTileService =
+ userState.getA11yFeatureToTileService();
+ Set<ComponentName> currentA11yTilesInQsPanel = userState.getA11yQsTilesInQsPanel();
+ for (ComponentName enabledService : enabledServices) {
+ ComponentName tileService =
+ a11yFeatureToTileService.getOrDefault(enabledService, null);
+ if (tileService != null && currentA11yTilesInQsPanel.contains(tileService)) {
+ somethingChanged |= targets.add(enabledService.flattenToString());
+ }
+ }
+
if (!somethingChanged) {
return;
}
@@ -3700,14 +3798,18 @@
return;
}
- final List<Pair<Integer, String>> shortcutTypeAndShortcutSetting = List.of(
+ final List<Pair<Integer, String>> shortcutTypeAndShortcutSetting = new ArrayList<>(3);
+ shortcutTypeAndShortcutSetting.add(
new Pair<>(ACCESSIBILITY_SHORTCUT_KEY,
- Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE),
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE));
+ shortcutTypeAndShortcutSetting.add(
new Pair<>(ACCESSIBILITY_BUTTON,
- Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS),
- new Pair<>(UserShortcutType.QUICK_SETTINGS,
- Settings.Secure.ACCESSIBILITY_QS_TARGETS)
- );
+ Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS));
+ if (android.view.accessibility.Flags.a11yQsShortcut()) {
+ shortcutTypeAndShortcutSetting.add(
+ new Pair<>(UserShortcutType.QUICK_SETTINGS,
+ Settings.Secure.ACCESSIBILITY_QS_TARGETS));
+ }
final ComponentName serviceName = service.getComponentName();
for (Pair<Integer, String> shortcutTypePair : shortcutTypeAndShortcutSetting) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index 063eafe..4b128f7 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -66,6 +66,8 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
/**
* Class that hold states and settings per user and share between
@@ -104,6 +106,15 @@
final ArraySet<String> mAccessibilityButtonTargets = new ArraySet<>();
private final ArraySet<String> mAccessibilityQsTargets = new ArraySet<>();
+ /**
+ * The QuickSettings tiles in the QS Panel. This can be different from
+ * {@link #mAccessibilityQsTargets} in that {@link #mA11yTilesInQsPanel} stores the
+ * TileService's or the a11y framework tile component names (e.g.
+ * {@link AccessibilityShortcutController#COLOR_INVERSION_TILE_COMPONENT_NAME}) instead of the
+ * A11y Feature's component names.
+ */
+ private final ArraySet<ComponentName> mA11yTilesInQsPanel = new ArraySet<>();
+
private final ServiceInfoChangeListener mServiceInfoChangeListener;
private ComponentName mServiceChangingSoftKeyboardMode;
@@ -566,7 +577,9 @@
pw.println("}");
pw.append(" button target:{").append(mTargetAssignedToAccessibilityButton);
pw.println("}");
- pw.append(" qs shortcut targets:" + mAccessibilityQsTargets);
+ pw.append(" qs shortcut targets:").append(mAccessibilityQsTargets.toString());
+ pw.println();
+ pw.append(" a11y tiles in QS panel:").append(mA11yTilesInQsPanel.toString());
pw.println();
pw.append(" Bound services:{");
final int serviceCount = mBoundServices.size();
@@ -1100,10 +1113,46 @@
return new ArraySet<>(mAccessibilityQsTargets);
}
+ public void updateA11yTilesInQsPanelLocked(Set<ComponentName> componentNames) {
+ mA11yTilesInQsPanel.clear();
+ mA11yTilesInQsPanel.addAll(componentNames);
+ }
+
+ /**
+ * Returns a copy of the a11y tiles that are in the QuickSettings panel
+ */
+ public ArraySet<ComponentName> getA11yQsTilesInQsPanel() {
+ return new ArraySet<>(mA11yTilesInQsPanel);
+ }
+
+ /**
+ * Returns a map of AccessibilityService or AccessibilityShortcut to its provided TileService
+ */
public Map<ComponentName, ComponentName> getA11yFeatureToTileService() {
Map<ComponentName, ComponentName> featureToTileServiceMap = new ArrayMap<>();
featureToTileServiceMap.putAll(mA11yServiceToTileService);
featureToTileServiceMap.putAll(mA11yActivityToTileService);
return featureToTileServiceMap;
}
+
+ /**
+ * Returns a map of TileService's componentName to the AccessibilityServiceInfo it ties to.
+ */
+ public Map<ComponentName, AccessibilityServiceInfo> getTileServiceToA11yServiceInfoMapLocked() {
+ Map<ComponentName, AccessibilityServiceInfo> tileServiceToA11yServiceInfoMap =
+ new ArrayMap<>();
+ Map<ComponentName, AccessibilityServiceInfo> a11yServiceToServiceInfoMap =
+ mInstalledServices.stream().collect(
+ Collectors.toMap(
+ AccessibilityServiceInfo::getComponentName,
+ Function.identity()));
+ for (Map.Entry<ComponentName, ComponentName> serviceToTile :
+ mA11yServiceToTileService.entrySet()) {
+ if (a11yServiceToServiceInfoMap.containsKey(serviceToTile.getKey())) {
+ tileServiceToA11yServiceInfoMap.put(serviceToTile.getValue(),
+ a11yServiceToServiceInfoMap.get(serviceToTile.getKey()));
+ }
+ }
+ return tileServiceToA11yServiceInfoMap;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 7f88b00..eb89503 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -88,6 +88,7 @@
import com.android.compatibility.common.util.TestUtils;
import com.android.internal.R;
+import com.android.internal.accessibility.AccessibilityShortcutController;
import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.accessibility.common.ShortcutConstants.FloatingMenuSize;
import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
@@ -1318,6 +1319,152 @@
}
}
+ @Test
+ @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+ public void notifyQuickSettingsTilesChanged_statusBarServiceNotGranted_throwsException() {
+ mTestableContext.getTestablePermissions().setPermission(
+ Manifest.permission.STATUS_BAR_SERVICE, PackageManager.PERMISSION_DENIED);
+ mockManageAccessibilityGranted(mTestableContext);
+
+ assertThrows(SecurityException.class,
+ () -> mA11yms.notifyQuickSettingsTilesChanged(
+ mA11yms.getCurrentUserState().mUserId,
+ List.of(
+ AccessibilityShortcutController.DALTONIZER_TILE_COMPONENT_NAME)));
+ }
+
+ @Test
+ @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+ public void notifyQuickSettingsTilesChanged_manageAccessibilityNotGranted_throwsException() {
+ mockStatusBarServiceGranted(mTestableContext);
+ mTestableContext.getTestablePermissions().setPermission(
+ Manifest.permission.STATUS_BAR_SERVICE, PackageManager.PERMISSION_DENIED);
+
+ assertThrows(SecurityException.class,
+ () -> mA11yms.notifyQuickSettingsTilesChanged(
+ mA11yms.getCurrentUserState().mUserId,
+ List.of(
+ AccessibilityShortcutController.DALTONIZER_TILE_COMPONENT_NAME)));
+ }
+
+ @Test
+ @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+ public void notifyQuickSettingsTilesChanged_qsTileChanges_updateA11yTilesInQsPanel() {
+ mockStatusBarServiceGranted(mTestableContext);
+ mockManageAccessibilityGranted(mTestableContext);
+ List<ComponentName> tiles = List.of(
+ AccessibilityShortcutController.DALTONIZER_TILE_COMPONENT_NAME,
+ AccessibilityShortcutController.COLOR_INVERSION_TILE_COMPONENT_NAME
+ );
+
+ mA11yms.notifyQuickSettingsTilesChanged(
+ mA11yms.getCurrentUserState().mUserId,
+ tiles
+ );
+
+ assertThat(
+ mA11yms.getCurrentUserState().getA11yQsTilesInQsPanel()
+ ).containsExactlyElementsIn(tiles);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+ public void notifyQuickSettingsTilesChanged_sameQsTiles_noUpdateToA11yTilesInQsPanel() {
+ notifyQuickSettingsTilesChanged_qsTileChanges_updateA11yTilesInQsPanel();
+ List<ComponentName> tiles =
+ mA11yms.getCurrentUserState().getA11yQsTilesInQsPanel().stream().toList();
+
+ mA11yms.notifyQuickSettingsTilesChanged(
+ mA11yms.getCurrentUserState().mUserId,
+ tiles
+ );
+
+ assertThat(
+ mA11yms.getCurrentUserState().getA11yQsTilesInQsPanel()
+ ).containsExactlyElementsIn(tiles);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+ public void notifyQuickSettingsTilesChanged_serviceWarningRequired_qsShortcutRemainDisabled() {
+ mockStatusBarServiceGranted(mTestableContext);
+ mockManageAccessibilityGranted(mTestableContext);
+ setupShortcutTargetServices();
+ ComponentName tile = new ComponentName(
+ TARGET_ALWAYS_ON_A11Y_SERVICE.getPackageName(),
+ TARGET_ALWAYS_ON_A11Y_SERVICE_TILE_CLASS);
+
+ mA11yms.notifyQuickSettingsTilesChanged(
+ mA11yms.getCurrentUserState().mUserId,
+ List.of(tile)
+ );
+
+ assertThat(mA11yms.getCurrentUserState().getA11yQsTargets()).doesNotContain(tile);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+ public void notifyQuickSettingsTilesChanged_serviceWarningNotRequired_qsShortcutEnabled() {
+ mockStatusBarServiceGranted(mTestableContext);
+ mockManageAccessibilityGranted(mTestableContext);
+ setupShortcutTargetServices();
+ final AccessibilityUserState userState = mA11yms.getCurrentUserState();
+ userState.mAccessibilityButtonTargets.clear();
+ userState.mAccessibilityButtonTargets.add(TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString());
+ ComponentName tile = new ComponentName(
+ TARGET_ALWAYS_ON_A11Y_SERVICE.getPackageName(),
+ TARGET_ALWAYS_ON_A11Y_SERVICE_TILE_CLASS);
+
+ mA11yms.notifyQuickSettingsTilesChanged(
+ mA11yms.getCurrentUserState().mUserId,
+ List.of(tile)
+ );
+
+ assertThat(mA11yms.getCurrentUserState().getA11yQsTargets())
+ .contains(TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString());
+ }
+
+ @Test
+ @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+ public void notifyQuickSettingsTilesChanged_addFrameworkTile_qsShortcutEnabled() {
+ mockStatusBarServiceGranted(mTestableContext);
+ mockManageAccessibilityGranted(mTestableContext);
+ List<ComponentName> tiles = List.of(
+ AccessibilityShortcutController.DALTONIZER_TILE_COMPONENT_NAME,
+ AccessibilityShortcutController.COLOR_INVERSION_TILE_COMPONENT_NAME
+ );
+
+ mA11yms.notifyQuickSettingsTilesChanged(
+ mA11yms.getCurrentUserState().mUserId,
+ tiles
+ );
+
+ assertThat(
+ mA11yms.getCurrentUserState().getA11yQsTargets()
+ ).containsExactlyElementsIn(List.of(
+ AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME.flattenToString(),
+ AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME.flattenToString())
+ );
+ }
+
+ @Test
+ @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
+ public void notifyQuickSettingsTilesChanged_removeFrameworkTile_qsShortcutDisabled() {
+ notifyQuickSettingsTilesChanged_addFrameworkTile_qsShortcutEnabled();
+ Set<ComponentName> qsTiles = mA11yms.getCurrentUserState().getA11yQsTilesInQsPanel();
+ qsTiles.remove(AccessibilityShortcutController.DALTONIZER_TILE_COMPONENT_NAME);
+
+ mA11yms.notifyQuickSettingsTilesChanged(
+ mA11yms.getCurrentUserState().mUserId,
+ qsTiles.stream().toList()
+ );
+
+ assertThat(
+ mA11yms.getCurrentUserState().getA11yQsTargets()
+ ).doesNotContain(
+ AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME.flattenToString());
+ }
+
private static AccessibilityServiceInfo mockAccessibilityServiceInfo(
ComponentName componentName) {
return mockAccessibilityServiceInfo(
@@ -1367,6 +1514,11 @@
PackageManager.PERMISSION_GRANTED);
}
+ private void mockStatusBarServiceGranted(TestableContext context) {
+ context.getTestablePermissions().setPermission(Manifest.permission.STATUS_BAR_SERVICE,
+ PackageManager.PERMISSION_GRANTED);
+ }
+
private void assertStartActivityWithExpectedComponentName(Context mockContext,
String componentName) {
verify(mockContext).startActivityAsUser(mIntentArgumentCaptor.capture(),
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
index 52a5d8f..b1964e2 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
@@ -30,6 +30,8 @@
import static com.android.server.accessibility.AccessibilityUserState.doesShortcutTargetsStringContain;
+import static com.google.common.truth.Truth.assertThat;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
@@ -45,6 +47,8 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.graphics.Color;
import android.platform.test.annotations.RequiresFlagsDisabled;
@@ -59,6 +63,7 @@
import androidx.test.InstrumentationRegistry;
import com.android.internal.R;
+import com.android.internal.accessibility.AccessibilityShortcutController;
import com.android.internal.util.test.FakeSettingsProvider;
import org.junit.After;
@@ -68,6 +73,9 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Map;
+import java.util.Set;
+
/** Tests for AccessibilityUserState */
public class AccessibilityUserStateTest {
@@ -431,7 +439,70 @@
assertEquals(focusStrokeWidthValue, mUserState.getFocusStrokeWidthLocked());
assertEquals(focusColorValue, mUserState.getFocusColorLocked());
+ }
+ @Test
+ public void updateA11yQsTargetLocked_valueUpdated() {
+ Set<String> newTargets = Set.of(
+ AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME.flattenToString(),
+ AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME.flattenToString()
+ );
+
+ mUserState.updateA11yQsTargetLocked(newTargets);
+
+ assertThat(mUserState.getA11yQsTargets()).isEqualTo(newTargets);
+ }
+
+ @Test
+ public void getA11yQsTargets_returnsCopiedData() {
+ updateA11yQsTargetLocked_valueUpdated();
+
+ Set<String> targets = mUserState.getA11yQsTargets();
+ targets.clear();
+
+ assertThat(mUserState.getA11yQsTargets()).isNotEmpty();
+ }
+
+ @Test
+ public void updateA11yTilesInQsPanelLocked_valueUpdated() {
+ Set<ComponentName> newTargets = Set.of(
+ AccessibilityShortcutController.DALTONIZER_TILE_COMPONENT_NAME,
+ AccessibilityShortcutController.COLOR_INVERSION_TILE_COMPONENT_NAME
+ );
+
+ mUserState.updateA11yTilesInQsPanelLocked(newTargets);
+
+ assertThat(mUserState.getA11yQsTilesInQsPanel()).isEqualTo(newTargets);
+ }
+
+ @Test
+ public void getA11yQsTilesInQsPanel_returnsCopiedData() {
+ updateA11yTilesInQsPanelLocked_valueUpdated();
+
+ Set<ComponentName> targets = mUserState.getA11yQsTilesInQsPanel();
+ targets.clear();
+
+ assertThat(mUserState.getA11yQsTilesInQsPanel()).isNotEmpty();
+ }
+
+ @Test
+ public void getTileServiceToA11yServiceInfoMapLocked() {
+ final ComponentName tileComponent =
+ new ComponentName(COMPONENT_NAME.getPackageName(), "FakeTileService");
+ ServiceInfo serviceInfo = new ServiceInfo();
+ serviceInfo.packageName = tileComponent.getPackageName();
+ serviceInfo.name = COMPONENT_NAME.getClassName();
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.serviceInfo = serviceInfo;
+ when(mMockServiceInfo.getTileServiceName()).thenReturn(tileComponent.getClassName());
+ when(mMockServiceInfo.getResolveInfo()).thenReturn(resolveInfo);
+ mUserState.mInstalledServices.add(mMockServiceInfo);
+ mUserState.updateTileServiceMapForAccessibilityServiceLocked();
+
+ Map<ComponentName, AccessibilityServiceInfo> actual =
+ mUserState.getTileServiceToA11yServiceInfoMapLocked();
+
+ assertThat(actual).containsExactly(tileComponent, mMockServiceInfo);
}
private int getSecureIntForUser(String key, int userId) {