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

Commit 918fcbe1 authored by Jason Hsu's avatar Jason Hsu Committed by Automerger Merge Worker
Browse files

Merge changes from topic "rhedjao_a11y_button_rollback" into rvc-dev am: f6e6cb11

Change-Id: I2efc42afad515f1826d79b020e4dd34632d4b184
parents b921ded2 f6e6cb11
Loading
Loading
Loading
Loading
+2 −10
Original line number Diff line number Diff line
@@ -4692,24 +4692,16 @@ public class SettingsProvider extends ContentProvider {

                if (currentVersion == 185) {
                    // Deprecate ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED, and migrate it
                    // to ACCESSIBILITY_BUTTON_TARGET_COMPONENT.
                    // to ACCESSIBILITY_BUTTON_TARGETS.
                    final SettingsState secureSettings = getSecureSettingsLocked(userId);
                    final Setting magnifyNavbarEnabled = secureSettings.getSettingLocked(
                            Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED);
                    if ("1".equals(magnifyNavbarEnabled.getValue())) {
                        secureSettings.insertSettingLocked(
                                Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
                                Secure.ACCESSIBILITY_BUTTON_TARGETS,
                                ACCESSIBILITY_SHORTCUT_TARGET_MAGNIFICATION_CONTROLLER,
                                null /* tag */, false /* makeDefault */,
                                SettingsState.SYSTEM_PACKAGE_NAME);
                    } else {
                        // Clear a11y button targets list setting. A11yManagerService will end up
                        // adding all legacy enabled services that want the button to the list, so
                        // there's no need to keep tracking them.
                        secureSettings.insertSettingLocked(
                                Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
                                null, null /* tag */, false /* makeDefault */,
                                SettingsState.SYSTEM_PACKAGE_NAME);
                    }
                    secureSettings.deleteSettingLocked(
                            Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED);
+1 −0
Original line number Diff line number Diff line
@@ -1081,6 +1081,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
            pw.append(", eventTypes="
                    + AccessibilityEvent.eventTypeToString(mEventTypes));
            pw.append(", notificationTimeout=" + mNotificationTimeout);
            pw.append(", requestA11yBtn=" + mRequestAccessibilityButton);
            pw.append("]");
        }
    }
+72 −23
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static android.view.accessibility.AccessibilityManager.ShortcutType;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import static com.android.internal.util.FunctionalUtils.ignoreRemoteException;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import static com.android.server.accessibility.AccessibilityUserState.doesShortcutTargetsStringContain;

import android.Manifest;
import android.accessibilityservice.AccessibilityGestureEvent;
@@ -876,6 +877,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
            throw new SecurityException("Caller does not hold permission "
                    + android.Manifest.permission.STATUS_BAR_SERVICE);
        }
        if (targetName == null) {
            synchronized (mLock) {
                final AccessibilityUserState userState = getCurrentUserStateLocked();
                targetName = userState.getTargetAssignedToAccessibilityButton();
            }
        }
        mMainHandler.sendMessage(obtainMessage(
                AccessibilityManagerService::performAccessibilityShortcutInternal, this,
                displayId, ACCESSIBILITY_BUTTON, targetName));
@@ -1828,7 +1835,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
        somethingChanged |= readMagnificationEnabledSettingsLocked(userState);
        somethingChanged |= readAutoclickEnabledSettingLocked(userState);
        somethingChanged |= readAccessibilityShortcutKeySettingLocked(userState);
        somethingChanged |= readAccessibilityButtonSettingsLocked(userState);
        somethingChanged |= readAccessibilityButtonTargetsLocked(userState);
        somethingChanged |= readAccessibilityButtonTargetComponentLocked(userState);
        somethingChanged |= readUserRecommendedUiTimeoutSettingsLocked(userState);
        return somethingChanged;
    }
@@ -1948,9 +1956,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
        return true;
    }

    private boolean readAccessibilityButtonSettingsLocked(AccessibilityUserState userState) {
    private boolean readAccessibilityButtonTargetsLocked(AccessibilityUserState userState) {
        final Set<String> targetsFromSetting = new ArraySet<>();
        readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
        readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
                userState.mUserId, targetsFromSetting, str -> str);

        final Set<String> currentTargets =
@@ -1964,6 +1972,23 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
        return true;
    }

    private boolean readAccessibilityButtonTargetComponentLocked(AccessibilityUserState userState) {
        final String componentId = Settings.Secure.getStringForUser(mContext.getContentResolver(),
                Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, userState.mUserId);
        if (TextUtils.isEmpty(componentId)) {
            if (userState.getTargetAssignedToAccessibilityButton() == null) {
                return false;
            }
            userState.setTargetAssignedToAccessibilityButton(null);
            return true;
        }
        if (componentId.equals(userState.getTargetAssignedToAccessibilityButton())) {
            return false;
        }
        userState.setTargetAssignedToAccessibilityButton(componentId);
        return true;
    }

    private boolean readUserRecommendedUiTimeoutSettingsLocked(AccessibilityUserState userState) {
        final int nonInteractiveUiTimeout = Settings.Secure.getIntForUser(
                mContext.getContentResolver(),
@@ -1984,7 +2009,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
    }

    /**
     * Check if the targets that will be enabled by the accessibility shortcut key is installed.
     * Check if the target that will be enabled by the accessibility shortcut key is installed.
     * If it isn't, remove it from the list and associated setting so a side loaded service can't
     * spoof the package name of the default service.
     */
@@ -2145,7 +2170,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub

    /**
     * 1) Update accessibility button availability to accessibility services.
     * 2) Check if the targets that will be enabled by the accessibility button is installed.
     * 2) Check if the target that will be enabled by the accessibility button is installed.
     *    If it isn't, remove it from the list and associated setting so a side loaded service can't
     *    spoof the package name of the default service.
     */
@@ -2172,8 +2197,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
        }

        // Update setting key with new value.
        persistColonDelimitedSetToSettingLocked(
                Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
        persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
                userState.mUserId, currentTargets, str -> str);
        scheduleNotifyClientsOfServicesStateChangeLocked(userState);
    }
@@ -2182,7 +2206,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
     * 1) Check if the service assigned to accessibility button target sdk version > Q.
     *    If it isn't, remove it from the list and associated setting.
     *    (It happens when an accessibility service package is downgraded.)
     * 2) Check if an enabled service targeting sdk version > Q and requesting a11y button is
     * 2) For a service targeting sdk version > Q and requesting a11y button, it should be in the
     *    enabled list if's assigned to a11y button.
     *    (It happens when an accessibility service package is same graded, and updated requesting
     *     a11y button flag)
     * 3) Check if an enabled service targeting sdk version > Q and requesting a11y button is
     *    assigned to a shortcut. If it isn't, assigns it to the accessibility button.
     *    (It happens when an enabled accessibility service package is upgraded.)
     *
@@ -2207,11 +2235,22 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
                return false;
            }
            if (serviceInfo.getResolveInfo().serviceInfo.applicationInfo
                    .targetSdkVersion > Build.VERSION_CODES.Q) {
                return false;
            }
                    .targetSdkVersion <= Build.VERSION_CODES.Q) {
                // A11y services targeting sdk version <= Q should not be in the list.
                Slog.v(LOG_TAG, "Legacy service " + componentName
                        + " should not in the button");
                return true;
            }
            final boolean requestA11yButton = (serviceInfo.flags
                    & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
            if (requestA11yButton && !userState.mEnabledServices.contains(componentName)) {
                // An a11y service targeting sdk version > Q and request A11y button and is assigned
                // to a11y btn should be in the enabled list.
                Slog.v(LOG_TAG, "Service requesting a11y button and be assigned to the button"
                        + componentName + " should be enabled state");
                return true;
            }
            return false;
        });
        boolean changed = (lastSize != buttonTargets.size());
        lastSize = buttonTargets.size();
@@ -2234,15 +2273,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
                    .targetSdkVersion > Build.VERSION_CODES.Q && requestA11yButton)) {
                return;
            }
            final String serviceName = serviceInfo.getComponentName().flattenToString();
            final String serviceName = componentName.flattenToString();
            if (TextUtils.isEmpty(serviceName)) {
                return;
            }
            if (shortcutKeyTargets.contains(serviceName) || buttonTargets.contains(serviceName)) {
            if (doesShortcutTargetsStringContain(buttonTargets, serviceName)
                    || doesShortcutTargetsStringContain(shortcutKeyTargets, serviceName)) {
                return;
            }
            // For enabled a11y services targeting sdk version > Q and requesting a11y button should
            // be assigned to a shortcut.
            Slog.v(LOG_TAG, "A enabled service requesting a11y button " + componentName
                    + " should be assign to the button or shortcut.");
            buttonTargets.add(serviceName);
        });
        changed |= (lastSize != buttonTargets.size());
@@ -2251,8 +2293,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
        }

        // Update setting key with new value.
        persistColonDelimitedSetToSettingLocked(
                Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
        persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
                userState.mUserId, buttonTargets, str -> str);
        scheduleNotifyClientsOfServicesStateChangeLocked(userState);
    }
@@ -2353,12 +2394,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
            return;
        }
        // In case the caller specified a target name
        if (targetName != null) {
            if (!shortcutTargets.contains(targetName)) {
                Slog.d(LOG_TAG, "Perform shortcut failed, invalid target name:" + targetName);
                return;
        if (targetName != null && !doesShortcutTargetsStringContain(shortcutTargets, targetName)) {
            Slog.v(LOG_TAG, "Perform shortcut failed, invalid target name:" + targetName);
            targetName = null;
        }
        } else {
        if (targetName == null) {
            // In case there are many targets assigned to the given shortcut.
            if (shortcutTargets.size() > 1) {
                showAccessibilityTargetsSelection(displayId, shortcutType);
@@ -2983,6 +3023,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
        private final Uri mAccessibilityButtonComponentIdUri = Settings.Secure.getUriFor(
                Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT);

        private final Uri mAccessibilityButtonTargetsUri = Settings.Secure.getUriFor(
                Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);

        private final Uri mUserNonInteractiveUiTimeoutUri = Settings.Secure.getUriFor(
                Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS);

@@ -3015,6 +3058,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
                    mAccessibilityShortcutServiceIdUri, false, this, UserHandle.USER_ALL);
            contentResolver.registerContentObserver(
                    mAccessibilityButtonComponentIdUri, false, this, UserHandle.USER_ALL);
            contentResolver.registerContentObserver(
                    mAccessibilityButtonTargetsUri, false, this, UserHandle.USER_ALL);
            contentResolver.registerContentObserver(
                    mUserNonInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL);
            contentResolver.registerContentObserver(
@@ -3061,7 +3106,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
                        onUserStateChangedLocked(userState);
                    }
                } else if (mAccessibilityButtonComponentIdUri.equals(uri)) {
                    if (readAccessibilityButtonSettingsLocked(userState)) {
                    if (readAccessibilityButtonTargetComponentLocked(userState)) {
                        onUserStateChangedLocked(userState);
                    }
                } else if (mAccessibilityButtonTargetsUri.equals(uri)) {
                    if (readAccessibilityButtonTargetsLocked(userState)) {
                        onUserStateChangedLocked(userState);
                    }
                } else if (mUserNonInteractiveUiTimeoutUri.equals(uri)
+58 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ import com.android.internal.accessibility.AccessibilityShortcutController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -96,6 +97,8 @@ class AccessibilityUserState {

    private ComponentName mServiceChangingSoftKeyboardMode;

    private String mTargetAssignedToAccessibilityButton;

    private boolean mBindInstantServiceAllowed;
    private boolean mIsAutoclickEnabled;
    private boolean mIsDisplayMagnificationEnabled;
@@ -152,6 +155,7 @@ class AccessibilityUserState {
        mTouchExplorationGrantedServices.clear();
        mAccessibilityShortcutKeyTargets.clear();
        mAccessibilityButtonTargets.clear();
        mTargetAssignedToAccessibilityButton = null;
        mIsTouchExplorationEnabled = false;
        mServiceHandlesDoubleTap = false;
        mRequestMultiFingerGestures = false;
@@ -469,6 +473,8 @@ class AccessibilityUserState {
            }
        }
        pw.println("}");
        pw.append("     button target:{").append(mTargetAssignedToAccessibilityButton);
        pw.println("}");
        pw.append("     Bound services:{");
        final int serviceCount = mBoundServices.size();
        for (int j = 0; j < serviceCount; j++) {
@@ -716,4 +722,56 @@ class AccessibilityUserState {
    public void setUserNonInteractiveUiTimeoutLocked(int timeout) {
        mUserNonInteractiveUiTimeout = timeout;
    }

    /**
     * Gets a shortcut target which is assigned to the accessibility button by the chooser
     * activity.
     *
     * @return The flattened component name or the system class name of the shortcut target.
     */
    public String getTargetAssignedToAccessibilityButton() {
        return mTargetAssignedToAccessibilityButton;
    }

    /**
     * Sets a shortcut target which is assigned to the accessibility button by the chooser
     * activity.
     *
     * @param target The flattened component name or the system class name of the shortcut target.
     */
    public void setTargetAssignedToAccessibilityButton(String target) {
        mTargetAssignedToAccessibilityButton = target;
    }

    /**
     * Whether or not the given target name is contained in the shortcut collection. Since the
     * component name string format could be short or long, this function un-flatten the component
     * name from the string in {@code shortcutTargets} and compared with the given target name.
     *
     * @param shortcutTargets The shortcut type.
     * @param targetName The target name.
     * @return {@code true} if the target is in the shortcut collection.
     */
    public static boolean doesShortcutTargetsStringContain(Collection<String> shortcutTargets,
            String targetName) {
        if (shortcutTargets == null || targetName == null) {
            return false;
        }
        // Some system features, such as magnification, don't have component name. Using string
        // compare first.
        if (shortcutTargets.contains(targetName)) {
            return true;
        }
        final ComponentName targetComponentName = ComponentName.unflattenFromString(targetName);
        if (targetComponentName == null) {
            return false;
        }
        for (String stringName : shortcutTargets) {
            if (!TextUtils.isEmpty(stringName)
                    && targetComponentName.equals(ComponentName.unflattenFromString(stringName))) {
                return true;
            }
        }
        return false;
    }
}
+36 −0
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@ import static android.view.accessibility.AccessibilityManager.STATE_FLAG_ACCESSI
import static android.view.accessibility.AccessibilityManager.STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED;
import static android.view.accessibility.AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;

import static com.android.server.accessibility.AccessibilityUserState.doesShortcutTargetsStringContain;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
@@ -41,6 +43,7 @@ import android.content.Context;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
import android.testing.DexmakerShareClassLoaderRule;
import android.util.ArraySet;

import com.android.internal.util.test.FakeSettingsProvider;

@@ -56,6 +59,12 @@ public class AccessibilityUserStateTest {

    private static final ComponentName COMPONENT_NAME =
            new ComponentName("com.android.server.accessibility", "AccessibilityUserStateTest");
    private static final ComponentName COMPONENT_NAME1 =
            new ComponentName("com.android.server.accessibility",
                    "com.android.server.accessibility.AccessibilityUserStateTest1");
    private static final ComponentName COMPONENT_NAME2 =
            new ComponentName("com.android.server.accessibility",
                    "com.android.server.accessibility.AccessibilityUserStateTest2");

    // Values of setting key SHOW_IME_WITH_HARD_KEYBOARD
    private static final int STATE_HIDE_IME = 0;
@@ -111,6 +120,7 @@ public class AccessibilityUserStateTest {
        mUserState.mTouchExplorationGrantedServices.add(COMPONENT_NAME);
        mUserState.mAccessibilityShortcutKeyTargets.add(COMPONENT_NAME.flattenToString());
        mUserState.mAccessibilityButtonTargets.add(COMPONENT_NAME.flattenToString());
        mUserState.setTargetAssignedToAccessibilityButton(COMPONENT_NAME.flattenToString());
        mUserState.setTouchExplorationEnabledLocked(true);
        mUserState.setDisplayMagnificationEnabledLocked(true);
        mUserState.setAutoclickEnabledLocked(true);
@@ -129,6 +139,7 @@ public class AccessibilityUserStateTest {
        assertTrue(mUserState.mTouchExplorationGrantedServices.isEmpty());
        assertTrue(mUserState.mAccessibilityShortcutKeyTargets.isEmpty());
        assertTrue(mUserState.mAccessibilityButtonTargets.isEmpty());
        assertNull(mUserState.getTargetAssignedToAccessibilityButton());
        assertFalse(mUserState.isTouchExplorationEnabledLocked());
        assertFalse(mUserState.isDisplayMagnificationEnabledLocked());
        assertFalse(mUserState.isAutoclickEnabledLocked());
@@ -285,6 +296,31 @@ public class AccessibilityUserStateTest {
        verify(mMockConnection).notifySoftKeyboardShowModeChangedLocked(eq(SHOW_MODE_HIDDEN));
    }

    @Test
    public void doesShortcutTargetsStringContain_returnFalse() {
        assertFalse(doesShortcutTargetsStringContain(null, null));
        assertFalse(doesShortcutTargetsStringContain(null,
                COMPONENT_NAME.flattenToShortString()));
        assertFalse(doesShortcutTargetsStringContain(new ArraySet<>(), null));

        final ArraySet<String> shortcutTargets = new ArraySet<>();
        shortcutTargets.add(COMPONENT_NAME.flattenToString());
        assertFalse(doesShortcutTargetsStringContain(shortcutTargets,
                COMPONENT_NAME1.flattenToString()));
    }

    @Test
    public void isAssignedToShortcutLocked_withDifferentTypeComponentString_returnTrue() {
        final ArraySet<String> shortcutTargets = new ArraySet<>();
        shortcutTargets.add(COMPONENT_NAME1.flattenToShortString());
        shortcutTargets.add(COMPONENT_NAME2.flattenToString());

        assertTrue(doesShortcutTargetsStringContain(shortcutTargets,
                COMPONENT_NAME1.flattenToString()));
        assertTrue(doesShortcutTargetsStringContain(shortcutTargets,
                COMPONENT_NAME2.flattenToShortString()));
    }

    @Test
    public void isShortcutTargetInstalledLocked_returnTrue() {
        mUserState.mInstalledServices.add(mMockServiceInfo);