diff options
3 files changed, 103 insertions, 1 deletions
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig index a50fb9a4c318..1c57dd3f5d5a 100644 --- a/services/accessibility/accessibility.aconfig +++ b/services/accessibility/accessibility.aconfig @@ -25,6 +25,16 @@ flag { } flag { + name: "clear_default_from_a11y_shortcut_target_service_restore" + namespace: "accessibility" + description: "Clears the config_defaultAccessibilityService from B&R for ACCESSIBILITY_SHORTCUT_TARGET_SERVICE." + bug: "341374402" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "compute_window_changes_on_a11y_v2" namespace: "accessibility" description: "Computes accessibility window changes in accessibility instead of wm package." @@ -209,4 +219,4 @@ flag { namespace: "accessibility" description: "Feature allows users to change color correction saturation for daltonizer." bug: "322829049" -}
\ No newline at end of file +} diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index c55e9eaaf721..f3dd635a4be2 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -2098,14 +2098,36 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub /** * Merges the old and restored value of * {@link Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE}. + * + * <p>Also clears out {@link R.string#config_defaultAccessibilityService} from + * the merged set if it was not present before restoring. */ private void restoreAccessibilityShortcutTargetService( String oldValue, String restoredValue) { final Set<String> targetsFromSetting = new ArraySet<>(); readColonDelimitedStringToSet(oldValue, str -> str, targetsFromSetting, /*doMerge=*/false); + final String defaultService = + mContext.getString(R.string.config_defaultAccessibilityService); + final ComponentName defaultServiceComponent = TextUtils.isEmpty(defaultService) + ? null : ComponentName.unflattenFromString(defaultService); + boolean shouldClearDefaultService = defaultServiceComponent != null + && !stringSetContainsComponentName(targetsFromSetting, defaultServiceComponent); readColonDelimitedStringToSet(restoredValue, str -> str, targetsFromSetting, /*doMerge=*/true); + if (Flags.clearDefaultFromA11yShortcutTargetServiceRestore()) { + if (shouldClearDefaultService && stringSetContainsComponentName( + targetsFromSetting, defaultServiceComponent)) { + Slog.i(LOG_TAG, "Removing default service " + defaultService + + " from restore of " + + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE); + targetsFromSetting.removeIf(str -> + defaultServiceComponent.equals(ComponentName.unflattenFromString(str))); + } + if (targetsFromSetting.isEmpty()) { + return; + } + } synchronized (mLock) { final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM); final Set<String> shortcutTargets = @@ -2120,6 +2142,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } + /** + * Returns {@code true} if the set contains the provided non-null {@link ComponentName}. + * + * <p>This ignores values in the set that are not valid {@link ComponentName}s. + */ + private boolean stringSetContainsComponentName(Set<String> set, + @NonNull ComponentName componentName) { + return componentName != null && set.stream() + .map(ComponentName::unflattenFromString) + .anyMatch(componentName::equals); + } + private int getClientStateLocked(AccessibilityUserState userState) { return userState.getClientStateLocked( mUiAutomationManager.canIntrospect(), 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 78cd2c15967b..fe5144ef7763 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java @@ -1707,6 +1707,64 @@ public class AccessibilityManagerServiceTest { .containsExactlyElementsIn(expected); } + @Test + @EnableFlags({ + android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE, + Flags.FLAG_CLEAR_DEFAULT_FROM_A11Y_SHORTCUT_TARGET_SERVICE_RESTORE}) + public void restoreA11yShortcutTargetService_alreadyHadDefaultService_doesNotClear() { + final String serviceDefault = TARGET_STANDARD_A11Y_SERVICE.flattenToString(); + mTestableContext.getOrCreateTestableResources().addOverride( + R.string.config_defaultAccessibilityService, serviceDefault); + final AccessibilityUserState userState = new AccessibilityUserState( + UserHandle.USER_SYSTEM, mTestableContext, mA11yms); + mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState); + setupShortcutTargetServices(userState); + + broadcastSettingRestored( + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, + /*previousValue=*/serviceDefault, + /*newValue=*/serviceDefault); + + final Set<String> expected = Set.of(serviceDefault); + assertThat(readStringsFromSetting( + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE)) + .containsExactlyElementsIn(expected); + assertThat(mA11yms.mUserStates.get(UserHandle.USER_SYSTEM) + .getShortcutTargetsLocked(UserShortcutType.HARDWARE)) + .containsExactlyElementsIn(expected); + } + + @Test + @EnableFlags({ + android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE, + Flags.FLAG_CLEAR_DEFAULT_FROM_A11Y_SHORTCUT_TARGET_SERVICE_RESTORE}) + public void restoreA11yShortcutTargetService_didNotHaveDefaultService_clearsDefaultService() { + final String serviceDefault = TARGET_STANDARD_A11Y_SERVICE.flattenToString(); + final String serviceRestored = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString(); + // Restored value from the broadcast contains both default and non-default service. + final String combinedRestored = String.join(":", serviceDefault, serviceRestored); + mTestableContext.getOrCreateTestableResources().addOverride( + R.string.config_defaultAccessibilityService, serviceDefault); + final AccessibilityUserState userState = new AccessibilityUserState( + UserHandle.USER_SYSTEM, mTestableContext, mA11yms); + mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState); + setupShortcutTargetServices(userState); + + broadcastSettingRestored( + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, + /*previousValue=*/null, + /*newValue=*/combinedRestored); + + // The default service is cleared from the final restored value. + final Set<String> expected = Set.of(serviceRestored); + assertThat(readStringsFromSetting( + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE)) + .containsExactlyElementsIn(expected); + assertThat(mA11yms.mUserStates.get(UserHandle.USER_SYSTEM) + .getShortcutTargetsLocked(UserShortcutType.HARDWARE)) + .containsExactlyElementsIn(expected); + } + private Set<String> readStringsFromSetting(String setting) { final Set<String> result = new ArraySet<>(); mA11yms.readColonDelimitedSettingToSet( |