Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit af7095ea authored by Riley Jones's avatar Riley Jones
Browse files

adjust migrateAccessibilityButtonSettings to check every shortcut type

some shortcuts were being unnecessarily migrated because we weren't checking the settings for every type.

I took the opportunity to also refactor A11yUserState to enable fetching multiple shortcut types at once.

Bug: 374373185
Test: atest AccessibilityManagerServiceTest AccessibilityUserStateTest, and manually verify the conditions in the bug no longer occur
Flag: android.provider.a11y_standalone_gesture_enabled
Change-Id: Ib9f62a20a88d09e3e2c1ecc3fec49d052d98b448
parent c6a025ef
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import static com.android.internal.accessibility.AccessibilityShortcutController
import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
import static com.android.internal.accessibility.common.ShortcutConstants.USER_SHORTCUT_TYPES;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.ALL;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.QUICK_SETTINGS;
@@ -3897,6 +3898,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
                userState.getShortcutTargetsLocked(HARDWARE);
        final Set<String> qsShortcutTargets =
                userState.getShortcutTargetsLocked(QUICK_SETTINGS);
        final Set<String> shortcutTargets = userState.getShortcutTargetsLocked(ALL);
        userState.mEnabledServices.forEach(componentName -> {
            if (packageName != null && componentName != null
                    && !packageName.equals(componentName.getPackageName())) {
@@ -3917,7 +3919,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
            if (TextUtils.isEmpty(serviceName)) {
                return;
            }
            if (doesShortcutTargetsStringContain(buttonTargets, serviceName)
            if (android.provider.Flags.a11yStandaloneGestureEnabled()) {
                if (doesShortcutTargetsStringContain(shortcutTargets, serviceName)) {
                    return;
                }
            } else if (doesShortcutTargetsStringContain(buttonTargets, serviceName)
                    || doesShortcutTargetsStringContain(shortcutKeyTargets, serviceName)
                    || doesShortcutTargetsStringContain(qsShortcutTargets, serviceName)) {
                return;
+35 −56
Original line number Diff line number Diff line
@@ -106,21 +106,17 @@ class AccessibilityUserState {

    final Set<ComponentName> mTouchExplorationGrantedServices = new HashSet<>();

    private final ArraySet<String> mAccessibilityShortcutKeyTargets = new ArraySet<>();

    private final ArraySet<String> mAccessibilityButtonTargets = new ArraySet<>();
    private final ArraySet<String> mAccessibilityGestureTargets = new ArraySet<>();
    private final ArraySet<String> mAccessibilityQsTargets = new ArraySet<>();
    private final HashMap<Integer, ArraySet<String>> mShortcutTargets = new HashMap<>();

    /**
     * The QuickSettings tiles in the QS Panel. This can be different from
     * {@link #mAccessibilityQsTargets} in that {@link #mA11yTilesInQsPanel} stores the
     * The QuickSettings tiles in the QS Panel. This can be different from the QS targets in
     * {@link #mShortcutTargets} 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.
     * <p/>
     * In addition, {@link #mA11yTilesInQsPanel} stores what's on the QS Panel, whereas
     * {@link #mAccessibilityQsTargets} stores the targets that configured qs as their shortcut and
     * {@link #mShortcutTargets} stores the targets that configured qs as their shortcut and
     * also grant full device control permission.
     */
    private final ArraySet<ComponentName> mA11yTilesInQsPanel = new ArraySet<>();
@@ -208,6 +204,11 @@ class AccessibilityUserState {
        mSupportWindowMagnification = mContext.getResources().getBoolean(
                R.bool.config_magnification_area) && mContext.getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_WINDOW_MAGNIFICATION);

        mShortcutTargets.put(HARDWARE, new ArraySet<>());
        mShortcutTargets.put(SOFTWARE, new ArraySet<>());
        mShortcutTargets.put(GESTURE, new ArraySet<>());
        mShortcutTargets.put(QUICK_SETTINGS, new ArraySet<>());
    }

    boolean isHandlingAccessibilityEventsLocked() {
@@ -233,10 +234,7 @@ class AccessibilityUserState {
        // Clear state persisted in settings.
        mEnabledServices.clear();
        mTouchExplorationGrantedServices.clear();
        mAccessibilityShortcutKeyTargets.clear();
        mAccessibilityButtonTargets.clear();
        mAccessibilityGestureTargets.clear();
        mAccessibilityQsTargets.clear();
        mShortcutTargets.forEach((type, targets) -> targets.clear());
        mA11yTilesInQsPanel.clear();
        mTargetAssignedToAccessibilityButton = null;
        mIsTouchExplorationEnabled = false;
@@ -541,7 +539,7 @@ class AccessibilityUserState {
    private void dumpShortcutTargets(
            PrintWriter pw, @UserShortcutType int shortcutType, String name) {
        pw.append("     ").append(name).append(":{");
        ArraySet<String> targets = getShortcutTargetsInternalLocked(shortcutType);
        ArraySet<String> targets = getShortcutTargetsLocked(shortcutType);
        int size = targets.size();
        for (int i = 0; i < size; i++) {
            if (i > 0) {
@@ -712,7 +710,7 @@ class AccessibilityUserState {
     */
    public boolean isShortcutMagnificationEnabledLocked() {
        for (int shortcutType : ShortcutConstants.USER_SHORTCUT_TYPES) {
            if (getShortcutTargetsInternalLocked(shortcutType)
            if (getShortcutTargetsLocked(shortcutType)
                    .contains(MAGNIFICATION_CONTROLLER_NAME)) {
                return true;
            }
@@ -787,44 +785,30 @@ class AccessibilityUserState {
        mMagnificationModes.put(displayId, mode);
    }

    /**
     * Disable both shortcuts' magnification function.
     */
    public void disableShortcutMagnificationLocked() {
        mAccessibilityShortcutKeyTargets.remove(MAGNIFICATION_CONTROLLER_NAME);
        mAccessibilityButtonTargets.remove(MAGNIFICATION_CONTROLLER_NAME);
    }

    /**
     * Returns a set which contains the flattened component names and the system class names
     * assigned to the given shortcut. The set is a defensive copy. To apply any changes to the set,
     * use {@link #updateShortcutTargetsLocked(Set, int)}
     * assigned to the given shortcut. <strong>The set is a defensive copy.</strong>
     * To apply any changes to the set, use {@link #updateShortcutTargetsLocked(Set, int)}
     *
     * @param shortcutType The shortcut type.
     * @param shortcutTypes The shortcut type or types (in bitmask format).
     * @return The array set of the strings
     */
    public ArraySet<String> getShortcutTargetsLocked(@UserShortcutType int shortcutType) {
        return new ArraySet<>(getShortcutTargetsInternalLocked(shortcutType));
    }

    private ArraySet<String> getShortcutTargetsInternalLocked(@UserShortcutType int shortcutType) {
        if (shortcutType == HARDWARE) {
            return mAccessibilityShortcutKeyTargets;
        } else if (shortcutType == SOFTWARE) {
            return mAccessibilityButtonTargets;
        } else if (shortcutType == GESTURE) {
            return mAccessibilityGestureTargets;
        } else if (shortcutType == QUICK_SETTINGS) {
            return mAccessibilityQsTargets;
        } else if ((shortcutType == TRIPLETAP
    public ArraySet<String> getShortcutTargetsLocked(int shortcutTypes) {
        ArraySet<String> targets = new ArraySet<>();
        for (int shortcutType : ShortcutConstants.USER_SHORTCUT_TYPES) {
            if ((shortcutTypes & shortcutType) != shortcutType) {
                continue;
            }
            if ((shortcutType == TRIPLETAP
                    && isMagnificationSingleFingerTripleTapEnabledLocked()) || (
                    shortcutType == TWOFINGER_DOUBLETAP
                            && isMagnificationTwoFingerTripleTapEnabledLocked())) {
            ArraySet<String> targets = new ArraySet<>();
                targets.add(MAGNIFICATION_CONTROLLER_NAME);
            return targets;
            } else if (mShortcutTargets.containsKey(shortcutType)) {
                targets.addAll(mShortcutTargets.get(shortcutType));
            }
        return new ArraySet<>();
        }
        return targets;
    }

    /**
@@ -843,8 +827,10 @@ class AccessibilityUserState {
        if ((shortcutType & mask) != 0) {
            throw new IllegalArgumentException("Tap shortcuts cannot be updated with target sets.");
        }

        final Set<String> currentTargets = getShortcutTargetsInternalLocked(shortcutType);
        if (!mShortcutTargets.containsKey(shortcutType)) {
            mShortcutTargets.put(shortcutType, new ArraySet<>());
        }
        ArraySet<String> currentTargets = mShortcutTargets.get(shortcutType);
        if (newTargets.equals(currentTargets)) {
            return false;
        }
@@ -904,7 +890,7 @@ class AccessibilityUserState {
        }

        // getting internal set lets us directly modify targets, as it's not a copy.
        Set<String> targets = getShortcutTargetsInternalLocked(shortcutType);
        Set<String> targets = mShortcutTargets.get(shortcutType);
        return targets.removeIf(name -> {
            ComponentName componentName;
            if (name == null
@@ -1169,13 +1155,6 @@ class AccessibilityUserState {
        );
    }

    /**
     * Returns a copy of the targets which has qs shortcut turned on
     */
    public ArraySet<String> getA11yQsTargets() {
        return new ArraySet<>(mAccessibilityQsTargets);
    }

    public void updateA11yTilesInQsPanelLocked(Set<ComponentName> componentNames) {
        mA11yTilesInQsPanel.clear();
        mA11yTilesInQsPanel.addAll(componentNames);
+5 −4
Original line number Diff line number Diff line
@@ -1615,7 +1615,8 @@ public class AccessibilityManagerServiceTest {
                List.of(tile)
        );

        assertThat(mA11yms.getCurrentUserState().getA11yQsTargets()).doesNotContain(tile);
        assertThat(mA11yms.getCurrentUserState()
                .getShortcutTargetsLocked(QUICK_SETTINGS)).doesNotContain(tile.flattenToString());
    }

    @Test
@@ -1636,7 +1637,7 @@ public class AccessibilityManagerServiceTest {
                List.of(tile)
        );

        assertThat(mA11yms.getCurrentUserState().getA11yQsTargets())
        assertThat(mA11yms.getCurrentUserState().getShortcutTargetsLocked(QUICK_SETTINGS))
                .contains(TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString());
    }

@@ -1656,7 +1657,7 @@ public class AccessibilityManagerServiceTest {
        );

        assertThat(
                mA11yms.getCurrentUserState().getA11yQsTargets()
                mA11yms.getCurrentUserState().getShortcutTargetsLocked(QUICK_SETTINGS)
        ).containsExactlyElementsIn(List.of(
                AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME.flattenToString(),
                AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME.flattenToString())
@@ -1676,7 +1677,7 @@ public class AccessibilityManagerServiceTest {
        );

        assertThat(
                mA11yms.getCurrentUserState().getA11yQsTargets()
                mA11yms.getCurrentUserState().getShortcutTargetsLocked(QUICK_SETTINGS)
        ).doesNotContain(
                AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME.flattenToString());
    }
+28 −11
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import static android.view.accessibility.AccessibilityManager.STATE_FLAG_HIGH_TE
import static android.view.accessibility.AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;

import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.ALL;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.QUICK_SETTINGS;
@@ -72,6 +73,7 @@ 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.UserShortcutType;
import com.android.internal.accessibility.util.ShortcutUtils;
import com.android.internal.util.test.FakeSettingsProvider;

import org.junit.After;
@@ -454,17 +456,7 @@ public class AccessibilityUserStateTest {

        mUserState.updateShortcutTargetsLocked(newTargets, QUICK_SETTINGS);

        assertThat(mUserState.getA11yQsTargets()).isEqualTo(newTargets);
    }

    @Test
    public void getA11yQsTargets_returnsCopiedData() {
        updateShortcutTargetsLocked_quickSettings_valueUpdated();

        Set<String> targets = mUserState.getA11yQsTargets();
        targets.clear();

        assertThat(mUserState.getA11yQsTargets()).isNotEmpty();
        assertThat(mUserState.getShortcutTargetsLocked(QUICK_SETTINGS)).isEqualTo(newTargets);
    }

    @Test
@@ -539,6 +531,31 @@ public class AccessibilityUserStateTest {
        assertThat(mUserState.isShortcutMagnificationEnabledLocked()).isFalse();
    }

    @Test
    public void getShortcutTargetsLocked_returnsCorrectTargets() {
        for (int shortcutType : ShortcutConstants.USER_SHORTCUT_TYPES) {
            if (((TRIPLETAP | TWOFINGER_DOUBLETAP) & shortcutType) == shortcutType) {
                continue;
            }
            Set<String> expectedSet = Set.of(ShortcutUtils.convertToKey(shortcutType));
            mUserState.updateShortcutTargetsLocked(expectedSet, shortcutType);

            assertThat(mUserState.getShortcutTargetsLocked(shortcutType))
                    .containsExactlyElementsIn(expectedSet);
        }
    }

    @Test
    public void getShortcutTargetsLocked_returnsCopiedData() {
        Set<String> set = Set.of("FOO", "BAR");
        mUserState.updateShortcutTargetsLocked(set, SOFTWARE);

        Set<String> targets = mUserState.getShortcutTargetsLocked(ALL);
        targets.clear();

        assertThat(mUserState.getShortcutTargetsLocked(ALL)).isNotEmpty();
    }

    private int getSecureIntForUser(String key, int userId) {
        return Settings.Secure.getIntForUser(mMockResolver, key, -1, userId);
    }