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

Commit 106fe732 authored by Phil Weaver's avatar Phil Weaver
Browse files

New accessibility shortcut.

Removing accessibility gesture from power dialog.

Adding new accessibility shortcut activated by holding both volume
buttons down. This shortcut is configurable by OEMs and users to
work with any installed accessibility service.

Bug: 30160335

Test: Added automated testing for the EnableAccessibilityController.
Manually toggled various services on and off.
Change-Id: I546bd29a2ab1ba64a0cbfd11e2004cdf85ee6cfd
parent 0e39a438
Loading
Loading
Loading
Loading
+19 −12
Original line number Diff line number Diff line
@@ -414,9 +414,9 @@ public class AccessibilityServiceInfo implements Parcelable {
    public int flags;

    /**
     * The unique string Id to identify the accessibility service.
     * The component name the accessibility service.
     */
    private String mId;
    private ComponentName mComponentName;

    /**
     * The Service that implements this accessibility service component.
@@ -464,7 +464,7 @@ public class AccessibilityServiceInfo implements Parcelable {
    public AccessibilityServiceInfo(ResolveInfo resolveInfo, Context context)
            throws XmlPullParserException, IOException {
        ServiceInfo serviceInfo = resolveInfo.serviceInfo;
        mId = new ComponentName(serviceInfo.packageName, serviceInfo.name).flattenToShortString();
        mComponentName = new ComponentName(serviceInfo.packageName, serviceInfo.name);
        mResolveInfo = resolveInfo;

        XmlResourceParser parser = null;
@@ -574,7 +574,14 @@ public class AccessibilityServiceInfo implements Parcelable {
     * @hide
     */
    public void setComponentName(ComponentName component) {
        mId = component.flattenToShortString();
        mComponentName = component;
    }

    /**
     * @hide
     */
    public ComponentName getComponentName() {
        return mComponentName;
    }

    /**
@@ -585,7 +592,7 @@ public class AccessibilityServiceInfo implements Parcelable {
     * @return The id.
     */
    public String getId() {
        return mId;
        return mComponentName.flattenToShortString();
    }

    /**
@@ -715,7 +722,7 @@ public class AccessibilityServiceInfo implements Parcelable {
        parcel.writeInt(feedbackType);
        parcel.writeLong(notificationTimeout);
        parcel.writeInt(flags);
        parcel.writeString(mId);
        parcel.writeParcelable(mComponentName, flagz);
        parcel.writeParcelable(mResolveInfo, 0);
        parcel.writeString(mSettingsActivityName);
        parcel.writeInt(mCapabilities);
@@ -729,7 +736,7 @@ public class AccessibilityServiceInfo implements Parcelable {
        feedbackType = parcel.readInt();
        notificationTimeout = parcel.readLong();
        flags = parcel.readInt();
        mId = parcel.readString();
        mComponentName = parcel.readParcelable(this.getClass().getClassLoader());
        mResolveInfo = parcel.readParcelable(null);
        mSettingsActivityName = parcel.readString();
        mCapabilities = parcel.readInt();
@@ -739,7 +746,7 @@ public class AccessibilityServiceInfo implements Parcelable {

    @Override
    public int hashCode() {
        return 31 * 1 + ((mId == null) ? 0 : mId.hashCode());
        return 31 * 1 + ((mComponentName == null) ? 0 : mComponentName.hashCode());
    }

    @Override
@@ -754,11 +761,11 @@ public class AccessibilityServiceInfo implements Parcelable {
            return false;
        }
        AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj;
        if (mId == null) {
            if (other.mId != null) {
        if (mComponentName == null) {
            if (other.mComponentName != null) {
                return false;
            }
        } else if (!mId.equals(other.mId)) {
        } else if (!mComponentName.equals(other.mComponentName)) {
            return false;
        }
        return true;
@@ -777,7 +784,7 @@ public class AccessibilityServiceInfo implements Parcelable {
        stringBuilder.append(", ");
        appendFlags(stringBuilder, flags);
        stringBuilder.append(", ");
        stringBuilder.append("id: ").append(mId);
        stringBuilder.append("id: ").append(getId());
        stringBuilder.append(", ");
        stringBuilder.append("resolveInfo: ").append(mResolveInfo);
        stringBuilder.append(", ");
+19 −1
Original line number Diff line number Diff line
@@ -5312,6 +5312,21 @@ public final class Settings {
         */
        public static final String ACCESSIBILITY_ENABLED = "accessibility_enabled";

        /**
         * Setting specifying if the accessibility shortcut dialog has been shown to this user.
         * @hide
         */
        public static final String ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN =
                "accessibility_shortcut_dialog_shown";

        /**
         * Setting specifying the the accessibility service to be toggled via the accessibility
         * shortcut. Must be its flattened {@link ComponentName}.
         * @hide
         */
        public static final String ACCESSIBILITY_SHORTCUT_TARGET_SERVICE =
                "accessibility_shortcut_target_service";

        /**
         * If touch exploration is enabled.
         */
@@ -6782,6 +6797,8 @@ public final class Settings {
            TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
            TOUCH_EXPLORATION_ENABLED,
            ACCESSIBILITY_ENABLED,
            ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
            ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
            ACCESSIBILITY_SPEAK_PASSWORD,
            ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
            ACCESSIBILITY_CAPTIONING_PRESET,
@@ -7071,7 +7088,9 @@ public final class Settings {
         * Setting whether the global gesture for enabling accessibility is enabled.
         * If this gesture is enabled the user will be able to perfrom it to enable
         * the accessibility state without visiting the settings app.
         *
         * @hide
         * No longer used. Should be removed once all dependencies have been updated.
         */
        public static final String ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED =
                "enable_accessibility_global_gesture_enabled";
@@ -9372,7 +9391,6 @@ public final class Settings {
            DOCK_SOUNDS_ENABLED,
            CHARGING_SOUNDS_ENABLED,
            USB_MASS_STORAGE_ENABLED,
            ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED,
            WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
            WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
            WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED,
+19 −0
Original line number Diff line number Diff line
@@ -82,6 +82,13 @@ public class ViewConfiguration {
     */
    private static final int GLOBAL_ACTIONS_KEY_TIMEOUT = 500;

    /**
     * Defines the duration in milliseconds a user needs to hold down the
     * appropriate button to bring up the accessibility shortcut (first time) or enable it
     * (once shortcut is configured).
     */
    private static final int A11Y_SHORTCUT_KEY_TIMEOUT = 3000;

    /**
     * Defines the duration in milliseconds we will wait to see if a touch event
     * is a tap or a scroll. If the user does not move within this interval, it is
@@ -784,6 +791,18 @@ public class ViewConfiguration {
        return mGlobalActionsKeyTimeout;
    }

    /**
     * The amount of time a user needs to press the relevant keys to activate the accessibility
     * shortcut.
     *
     * @return how long a user needs to press the relevant keys to activate the accessibility
     *   shortcut.
     * @hide
     */
    public long getAccessibilityShortcutKeyTimeout() {
        return A11Y_SHORTCUT_KEY_TIMEOUT;
    }

    /**
     * The amount of friction applied to scrolls and flings.
     *
+64 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_ENABLE_
import android.Manifest;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
@@ -241,6 +242,8 @@ public final class AccessibilityManager {
     * @hide
     */
    public AccessibilityManager(Context context, IAccessibilityManager service, int userId) {
        // Constructor can't be chained because we can't create an instance of an inner class
        // before calling another constructor.
        mHandler = new MyHandler(context.getMainLooper());
        mUserId = userId;
        synchronized (mLock) {
@@ -248,6 +251,23 @@ public final class AccessibilityManager {
        }
    }

    /**
     * Create an instance.
     *
     * @param handler The handler to use
     * @param service An interface to the backing service.
     * @param userId User id under which to run.
     *
     * @hide
     */
    public AccessibilityManager(Handler handler, IAccessibilityManager service, int userId) {
        mHandler = handler;
        mUserId = userId;
        synchronized (mLock) {
            tryConnectToServiceLocked(service);
        }
    }

    /**
     * @hide
     */
@@ -646,6 +666,30 @@ public final class AccessibilityManager {
        }
    }

    /**
     * Find an installed service with the specified {@link ComponentName}.
     *
     * @param componentName The name to match to the service.
     *
     * @return The info corresponding to the installed service, or {@code null} if no such service
     * is installed.
     * @hide
     */
    public AccessibilityServiceInfo getInstalledServiceInfoWithComponentName(
            ComponentName componentName) {
        final List<AccessibilityServiceInfo> installedServiceInfos =
                getInstalledAccessibilityServiceList();
        if ((installedServiceInfos == null) || (componentName == null)) {
            return null;
        }
        for (int i = 0; i < installedServiceInfos.size(); i++) {
            if (componentName.equals(installedServiceInfos.get(i).getComponentName())) {
                return installedServiceInfos.get(i);
            }
        }
        return null;
    }

    /**
     * Adds an accessibility interaction connection interface for a given window.
     * @param windowToken The window token to which a connection is added.
@@ -693,6 +737,26 @@ public final class AccessibilityManager {
        }
    }

    /**
     * Perform the accessibility shortcut if the caller has permission.
     *
     * @hide
     */
    public void performAccessibilityShortcut() {
        final IAccessibilityManager service;
        synchronized (mLock) {
            service = getServiceLocked();
            if (service == null) {
                return;
            }
        }
        try {
            service.performAccessibilityShortcut();
        } catch (RemoteException re) {
            Log.e(LOG_TAG, "Error performing accessibility shortcut. ", re);
        }
    }

    private IAccessibilityManager getServiceLocked() {
        if (mService == null) {
            tryConnectToServiceLocked(null);
+2 −3
Original line number Diff line number Diff line
@@ -60,7 +60,6 @@ interface IAccessibilityManager {

    IBinder getWindowToken(int windowId, int userId);

    void enableAccessibilityService(in ComponentName service, int userId);

    void disableAccessibilityService(in ComponentName service, int userId);
    // Requires WRITE_SECURE_SETTINGS
    void performAccessibilityShortcut();
}
Loading