diff options
| author | 2024-03-08 01:51:45 +0000 | |
|---|---|---|
| committer | 2024-03-12 00:52:46 +0000 | |
| commit | 9fd04c906a31b2f2055a0cab44cfa24d15005323 (patch) | |
| tree | c2dc0e59503e017967b802236c17228a4f21e574 | |
| parent | 44174063983b7719001a38fb268839b5c09a590a (diff) | |
Updating ACCESSIBILITY_QS_TARGETS when user moves the A11y QS tiles in the QS Panel
Bug: 314843909
Test: manual (add/remove a11y tile in QS panel and check if the qs
shortcut option is selected/deselected in the Settings app if the tile
is not associated to an a11y feature that requires the user to grant
full device control permission)
Test: atest AccessibilityManagerServiceTest
Test: atest AccessibilityUserStateTest
Flag: ACONFIG android.view.accessibility.a11y_qs_shortcut
Change-Id: I92dba0a1d0581f926d17fcf2693129dcf80d89a8
5 files changed, 395 insertions, 21 deletions
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl index e215950fe26a..614df7c10456 100644 --- a/core/java/android/view/accessibility/IAccessibilityManager.aidl +++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl @@ -142,7 +142,7 @@ interface IAccessibilityManager { @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 ff48c9dd7c6e..2a1424d929c5 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -1757,20 +1757,101 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } @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"); + + 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; - Slog.d(LOG_TAG, TextUtils.formatSimple( - "notifyQuickSettingsTilesChanged userId: %d, tileComponentNames: %s", - userId, tileComponentNames)); - // TODO (b/314843909): in the follow up cl // 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); + } } /** @@ -3727,18 +3808,35 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub /** * 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; } @@ -3766,14 +3864,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub 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 063eafebdfcb..4b128f75f4d2 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.Iterator; 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 @@ class AccessibilityUserState { 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 @@ class AccessibilityUserState { 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 @@ class AccessibilityUserState { 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 7ea722be9878..bdbdd85a9aab 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java @@ -89,6 +89,7 @@ import androidx.test.filters.SmallTest; 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; @@ -1340,6 +1341,152 @@ public class AccessibilityManagerServiceTest { } } + @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( @@ -1389,6 +1536,11 @@ public class AccessibilityManagerServiceTest { 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 52a5d8f6d952..b1964e23ff53 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 android.view.accessibility.AccessibilityManager.STATE_FLAG_TOUCH_E 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.accessibilityservice.AccessibilityServiceInfo; 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 android.view.Display; 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.junit.Test; 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 @@ public class AccessibilityUserStateTest { 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) { |