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

Commit 688a6977 authored by Svetoslav's avatar Svetoslav Committed by Svetoslav Ganov
Browse files

Replacing accessibility service permissions with capability attributes.

Accessibility services can perform special operations such as retrieve
the screen content, enable explore by touch, etc. To ensure the user
is aware that the service will perform special operations we were using
permissions. However, the special operations cannot be performed unless
the service is really enabled by the user and it is at this point that
we want to notify the user about the service capabilities.

This change adds capability attributes to the accessibility service's
meta-data XML file. The service has to declare the capability and when
it is enabled we show the user the capabilities in the warining dialog.

bug:8633951

Change-Id: Id3442dc71dad018e606888afdc40834682fdb037
parent a407994b
Loading
Loading
Loading
Loading
+11 −3
Original line number Diff line number Diff line
@@ -37,8 +37,6 @@ package android {
    field public static final java.lang.String CALL_PHONE = "android.permission.CALL_PHONE";
    field public static final java.lang.String CALL_PRIVILEGED = "android.permission.CALL_PRIVILEGED";
    field public static final java.lang.String CAMERA = "android.permission.CAMERA";
    field public static final java.lang.String CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = "android.permission.CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
    field public static final java.lang.String CAN_REQUEST_TOUCH_EXPLORATION_MODE = "android.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE";
    field public static final java.lang.String CHANGE_COMPONENT_ENABLED_STATE = "android.permission.CHANGE_COMPONENT_ENABLED_STATE";
    field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION";
    field public static final java.lang.String CHANGE_NETWORK_STATE = "android.permission.CHANGE_NETWORK_STATE";
@@ -322,6 +320,9 @@ package android {
    field public static final int cacheColorHint = 16843009; // 0x1010101
    field public static final int calendarViewShown = 16843596; // 0x101034c
    field public static final int calendarViewStyle = 16843613; // 0x101035d
    field public static final int canRequestEnhancedWebAccessibility = 16843735; // 0x10103d7
    field public static final int canRequestFilterKeyEvents = 16843736; // 0x10103d8
    field public static final int canRequestTouchExplorationMode = 16843734; // 0x10103d6
    field public static final int canRetrieveWindowContent = 16843653; // 0x1010385
    field public static final int candidatesTextStyleSpans = 16843312; // 0x1010230
    field public static final deprecated int capitalize = 16843113; // 0x1010169
@@ -2107,16 +2108,22 @@ package android.accessibilityservice {
  public class AccessibilityServiceInfo implements android.os.Parcelable {
    ctor public AccessibilityServiceInfo();
    method public static java.lang.String capabilityToString(int);
    method public int describeContents();
    method public static java.lang.String feedbackTypeToString(int);
    method public static java.lang.String flagToString(int);
    method public boolean getCanRetrieveWindowContent();
    method public deprecated boolean getCanRetrieveWindowContent();
    method public int getCapabilities();
    method public deprecated java.lang.String getDescription();
    method public java.lang.String getId();
    method public android.content.pm.ResolveInfo getResolveInfo();
    method public java.lang.String getSettingsActivityName();
    method public java.lang.String loadDescription(android.content.pm.PackageManager);
    method public void writeToParcel(android.os.Parcel, int);
    field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
    field public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 8; // 0x8
    field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
    field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
    field public static final android.os.Parcelable.Creator CREATOR;
    field public static final int DEFAULT = 1; // 0x1
    field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff
@@ -2129,6 +2136,7 @@ package android.accessibilityservice {
    field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
    field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
    field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
    field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
    field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
    field public int eventTypes;
    field public int feedbackType;
+2 −0
Original line number Diff line number Diff line
@@ -308,6 +308,8 @@ public abstract class AccessibilityService extends Service {
     *     android:accessibilityFlags="flagDefault"
     *     android:settingsActivity="foo.bar.TestBackActivity"
     *     android:canRetrieveWindowContent="true"
     *     android:canRequestTouchExplorationMode="true"
     *     android:canRequestEnhancedWebAccessibility="true"
     *     . . .
     * /&gt;</pre>
     */
+199 −15
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.util.TypedValue;
import android.util.Xml;
import android.view.View;
@@ -38,7 +39,12 @@ import android.view.accessibility.AccessibilityNodeInfo;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import com.android.internal.R;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * This class describes an {@link AccessibilityService}. The system notifies an
@@ -60,6 +66,49 @@ public class AccessibilityServiceInfo implements Parcelable {

    private static final String TAG_ACCESSIBILITY_SERVICE = "accessibility-service";

    /**
     * Capability: This accessibility service can retrieve the active window content.
     */
    public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 0x00000001;

    /**
     * Capability: This accessibility service can request touch exploration mode in which
     * touched items are spoken aloud and the UI can be explored via gestures.
     */
    public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 0x00000002;

    /**
     * Capability: This accessibility service can request enhanced web accessibility
     * enhancements. For example, installing scripts to make app content more accessible.
     */
    public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000004;

    /**
      * Capability: This accessibility service can request to filter the key event stream.
     */
    public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 0x00000008;

    private static final SparseArray<CapabilityInfo> sAvailableCapabilityInfos =
            new SparseArray<CapabilityInfo>();
    static {
        sAvailableCapabilityInfos.put(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
                new CapabilityInfo(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
                        R.string.capability_title_canRetrieveWindowContent,
                        R.string.capability_desc_canRetrieveWindowContent));
        sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
                new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
                        R.string.capability_title_canRequestTouchExploration,
                        R.string.capability_desc_canRequestTouchExploration));
        sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
                new CapabilityInfo(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
                        R.string.capability_title_canRequestEnhancedWebAccessibility,
                        R.string.capability_desc_canRequestEnhancedWebAccessibility));
        sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
                new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
                        R.string.capability_title_canRequestFilterKeyEvents,
                        R.string.capability_desc_canRequestFilterKeyEvents));
    }

    /**
     * Denotes spoken feedback.
     */
@@ -152,9 +201,11 @@ public class AccessibilityServiceInfo implements Parcelable {
     * <p>
     * For accessibility services targeting API version higher than
     * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} that want to set
     * this flag have to request the
     * {@link android.Manifest.permission#CAN_REQUEST_TOUCH_EXPLORATION_MODE}
     * permission or the flag will be ignored.
     * this flag have to declare this capability in their meta-data by setting
     * the attribute {@link android.R.attr#canRequestTouchExplorationMode
     * canRequestTouchExplorationMode} to true, otherwise this flag will
     * be ignored. For how to declare the meta-data of a service refer to
     * {@value AccessibilityService#SERVICE_META_DATA}.
     * </p>
     * <p>
     * Services targeting API version equal to or lower than
@@ -175,9 +226,11 @@ public class AccessibilityServiceInfo implements Parcelable {
     * device will not have enhanced web accessibility enabled since there may be
     * another enabled service that requested it.
     * <p>
     * Clients that want to set this flag have to request the
     * {@link android.Manifest.permission#CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY}
     * permission or the flag will be ignored.
     * Services that want to set this flag have to declare this capability
     * in their meta-data by setting the attribute {@link android.R.attr
     * #canRequestEnhancedWebAccessibility canRequestEnhancedWebAccessibility} to
     * true, otherwise this flag will be ignored. For how to declare the meta-data
     * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
     * </p>
     */
    public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000008;
@@ -191,6 +244,25 @@ public class AccessibilityServiceInfo implements Parcelable {
     */
    public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;

    /**
     * This flag requests from the system to filter key events. If this flag
     * is set the accessibility service will receive the key events before
     * applications allowing it implement global shortcuts. Setting this flag
     * does not guarantee that this service will filter key events since only
     * one service can do so at any given time. This avoids user confusion due
     * to behavior change in case different key filtering services are enabled.
     * If there is already another key filtering service enabled, this one will
     * not receive key events.
     * <p>
     * Services that want to set this flag have to declare this capability
     * in their meta-data by setting the attribute {@link android.R.attr
     * #canRequestFilterKeyEvents canRequestFilterKeyEvents} to true,
     * otherwise this flag will be ignored. For how to declare the meta-data
     * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
     * </p>
     */
    public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 0x00000020;

    /**
     * The event types an {@link AccessibilityService} is interested in.
     * <p>
@@ -259,6 +331,9 @@ public class AccessibilityServiceInfo implements Parcelable {
     * @see #DEFAULT
     * @see #FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
     * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE
     * @see #FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY
     * @see #FLAG_REQUEST_FILTER_KEY_EVENTS
     * @see #FLAG_REPORT_VIEW_IDS
     */
    public int flags;

@@ -279,9 +354,9 @@ public class AccessibilityServiceInfo implements Parcelable {
    private String mSettingsActivityName;

    /**
     * Flag whether this accessibility service can retrieve window content.
     * Bit mask with capabilities of this service.
     */
    private boolean mCanRetrieveWindowContent;
    private int mCapabilities;

    /**
     * Resource id of the description of the accessibility service.
@@ -360,9 +435,22 @@ public class AccessibilityServiceInfo implements Parcelable {
                    com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0);
            mSettingsActivityName = asAttributes.getString(
                    com.android.internal.R.styleable.AccessibilityService_settingsActivity);
            mCanRetrieveWindowContent = asAttributes.getBoolean(
                    com.android.internal.R.styleable.AccessibilityService_canRetrieveWindowContent,
                    false);
            if (asAttributes.getBoolean(com.android.internal.R.styleable
                    .AccessibilityService_canRetrieveWindowContent, false)) {
                mCapabilities |= CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT;
            }
            if (asAttributes.getBoolean(com.android.internal.R.styleable
                    .AccessibilityService_canRequestTouchExplorationMode, false)) {
                mCapabilities |= CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION;
            }
            if (asAttributes.getBoolean(com.android.internal.R.styleable
                    .AccessibilityService_canRequestEnhancedWebAccessibility, false)) {
                mCapabilities |= CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY;
            }
            if (asAttributes.getBoolean(com.android.internal.R.styleable
                    .AccessibilityService_canRequestFilterKeyEvents, false)) {
                mCapabilities |= CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS;
            }
            TypedValue peekedValue = asAttributes.peekValue(
                    com.android.internal.R.styleable.AccessibilityService_description);
            if (peekedValue != null) {
@@ -446,9 +534,26 @@ public class AccessibilityServiceInfo implements Parcelable {
     *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
     * </p>
     * @return True if window content can be retrieved.
     *
     * @deprecated Use {@link #getCapabilities()}.
     */
    public boolean getCanRetrieveWindowContent() {
        return mCanRetrieveWindowContent;
        return (mCapabilities & CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0;
    }

    /**
     * Returns the bit mask of capabilities this accessibility service has such as
     * being able to retrieve the active window content, etc.
     *
     * @return The capability bit mask.
     *
     * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
     * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
     * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
     * @see #CAPABILITY_FILTER_KEY_EVENTS
     */
    public int getCapabilities() {
        return mCapabilities;
    }

    /**
@@ -502,7 +607,7 @@ public class AccessibilityServiceInfo implements Parcelable {
        parcel.writeString(mId);
        parcel.writeParcelable(mResolveInfo, 0);
        parcel.writeString(mSettingsActivityName);
        parcel.writeInt(mCanRetrieveWindowContent ? 1 : 0);
        parcel.writeInt(mCapabilities);
        parcel.writeInt(mDescriptionResId);
        parcel.writeString(mNonLocalizedDescription);
    }
@@ -516,7 +621,7 @@ public class AccessibilityServiceInfo implements Parcelable {
        mId = parcel.readString();
        mResolveInfo = parcel.readParcelable(null);
        mSettingsActivityName = parcel.readString();
        mCanRetrieveWindowContent = (parcel.readInt() == 1);
        mCapabilities = parcel.readInt();
        mDescriptionResId = parcel.readInt();
        mNonLocalizedDescription = parcel.readString();
    }
@@ -567,7 +672,7 @@ public class AccessibilityServiceInfo implements Parcelable {
        stringBuilder.append(", ");
        stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName);
        stringBuilder.append(", ");
        stringBuilder.append("retrieveScreenContent: ").append(mCanRetrieveWindowContent);
        appendCapabilities(stringBuilder, mCapabilities);
        return stringBuilder.toString();
    }

@@ -628,6 +733,20 @@ public class AccessibilityServiceInfo implements Parcelable {
        stringBuilder.append("]");
    }

    private static void appendCapabilities(StringBuilder stringBuilder, int capabilities) {
        stringBuilder.append("capabilities:");
        stringBuilder.append("[");
        while (capabilities != 0) {
            final int capabilityBit = (1 << Integer.numberOfTrailingZeros(capabilities));
            stringBuilder.append(capabilityToString(capabilityBit));
            capabilities &= ~capabilityBit;
            if (capabilities != 0) {
                stringBuilder.append(", ");
            }
        }
        stringBuilder.append("]");
    }

    /**
     * Returns the string representation of a feedback type. For example,
     * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN.
@@ -699,11 +818,76 @@ public class AccessibilityServiceInfo implements Parcelable {
                return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS";
            case FLAG_REQUEST_TOUCH_EXPLORATION_MODE:
                return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE";
            case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
                return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
            case FLAG_REPORT_VIEW_IDS:
                return "FLAG_REPORT_VIEW_IDS";
            case FLAG_REQUEST_FILTER_KEY_EVENTS:
                return "FLAG_REQUEST_FILTER_KEY_EVENTS";
            default:
                return null;
        }
    }

    /**
     * Returns the string representation of a capability. For example,
     * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented
     * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT.
     *
     * @param capability The capability.
     * @return The string representation.
     */
    public static String capabilityToString(int capability) {
        switch (capability) {
            case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT:
                return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT";
            case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION:
                return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION";
            case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
                return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
            case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS:
                return "CAPABILITY_CAN_FILTER_KEY_EVENTS";
            default:
                return "UNKNOWN";
        }
    }

    /**
     * @hide
     * @return The list of {@link CapabilityInfo} objects.
     */
    public List<CapabilityInfo> getCapabilityInfos() {
        if (mCapabilities == 0) {
            return Collections.emptyList();
        }
        int capabilities = mCapabilities;
        List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>();
        while (capabilities != 0) {
            final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities);
            capabilities &= ~capabilityBit;
            CapabilityInfo capabilityInfo = sAvailableCapabilityInfos.get(capabilityBit);
            if (capabilityInfo != null) {
                capabilityInfos.add(capabilityInfo);
            }
        }
        return capabilityInfos;
    }

    /**
     * @hide
     */
    public static final class CapabilityInfo {
        public final int capability;
        public final int titleResId;
        public final int descResId;

        public CapabilityInfo(int capability, int titleResId, int descResId) {
            this.capability = capability;
            this.titleResId = titleResId;
            this.descResId = descResId;
        }
    }

    /**
     * @see Parcelable.Creator
     */
+0 −14
Original line number Diff line number Diff line
@@ -554,20 +554,6 @@
        android:description="@string/permgroupdesc_accessibilityFeatures"
        android:priority="380" />

    <!-- Allows an accessibility service to request touch exploration mode. -->
    <permission android:name="android.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE"
        android:permissionGroup="android.permission-group.ACCESSIBILITY_FEATURES"
        android:label="@string/permlab_canRequestTouchExplorationMode"
        android:description="@string/permdesc_canRequestTouchExplorationMode"
        android:protectionLevel="dangerous" />

    <!-- Allows an accessibility service to request enhanced web accessibility. -->
    <permission android:name="android.permission.CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY"
        android:permissionGroup="android.permission-group.ACCESSIBILITY_FEATURES"
        android:label="@string/permlab_canRequestEnahncedWebAccessibility"
        android:description="@string/permdesc_canRequestEnahncedWebAccessibility"
        android:protectionLevel="dangerous" />

    <!-- ======================================= -->
    <!-- Permissions for accessing location info -->
    <!-- ======================================= -->
+31 −1
Original line number Diff line number Diff line
@@ -2521,13 +2521,43 @@
            <flag name="flagRequestTouchExplorationMode" value="0x00000004" />
            <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY} -->
            <flag name="flagRequestEnhancedWebAccessibility" value="0x00000008" />
            <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS} -->
            <flag name="flagReportViewIds" value="0x00000010" />
            <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_FILTER_KEY_EVENTS} -->
            <flag name="flagRequestFilterKeyEvents" value="0x00000020" />
        </attr>
        <!-- Component name of an activity that allows the user to modify
             the settings for this service. This setting cannot be changed at runtime. -->
        <attr name="settingsActivity" />
        <!-- Flag whether the accessibility service wants to be able to retrieve the
        <!-- Attribute whether the accessibility service wants to be able to retrieve the
             active window content. This setting cannot be changed at runtime. -->
        <attr name="canRetrieveWindowContent" format="boolean" />
        <!-- Attribute whether the accessibility service wants to be able to request touch
             exploration mode in which touched items are spoken aloud and the UI can be
             explored via gestures.
             <p>
             Required to allow setting the {@link android.accessibilityservice
             #AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} flag.
             </p>
         -->
        <attr name="canRequestTouchExplorationMode" format="boolean" />
        <!-- Attribute whether the accessibility service wants to be able to request enhanced
             web accessibility enhancements. For example, installing scripts to make app
             content more accessible.
             <p>
             Required to allow setting the {@link android.accessibilityservice
             #AccessibilityServiceInfo#FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY} flag.
             </p>
         -->
        <attr name="canRequestEnhancedWebAccessibility" format="boolean" />
        <!-- Attribute whether the accessibility service wants to be able to request to
             filter key events.
             <p>
             Required to allow setting the {@link android.accessibilityservice
             #AccessibilityServiceInfo#FLAG_REQUEST_FILTER_KEY_EVENTS} flag.
             </p>
         -->
        <attr name="canRequestFilterKeyEvents" format="boolean" />
        <!-- Short description of the accessibility serivce purpose or behavior.-->
        <attr name="description" />
    </declare-styleable>
Loading