/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.support.v4.accessibilityservice; import android.accessibilityservice.AccessibilityService; import android.accessibilityservice.AccessibilityServiceInfo; import android.content.pm.ResolveInfo; import android.os.Build; import android.view.View; /** * Helper for accessing features in {@link android.accessibilityservice.AccessibilityService} * introduced after API level 4 in a backwards compatible fashion. */ public final class AccessibilityServiceInfoCompat { static interface AccessibilityServiceInfoVersionImpl { public String getId(AccessibilityServiceInfo info); public ResolveInfo getResolveInfo(AccessibilityServiceInfo info); public boolean getCanRetrieveWindowContent(AccessibilityServiceInfo info); public String getDescription(AccessibilityServiceInfo info); public String getSettingsActivityName(AccessibilityServiceInfo info); public int getCapabilities(AccessibilityServiceInfo info); } static class AccessibilityServiceInfoStubImpl implements AccessibilityServiceInfoVersionImpl { public boolean getCanRetrieveWindowContent(AccessibilityServiceInfo info) { return false; } public String getDescription(AccessibilityServiceInfo info) { return null; } public String getId(AccessibilityServiceInfo info) { return null; } public ResolveInfo getResolveInfo(AccessibilityServiceInfo info) { return null; } public String getSettingsActivityName(AccessibilityServiceInfo info) { return null; } public int getCapabilities(AccessibilityServiceInfo info) { return 0; } } static class AccessibilityServiceInfoIcsImpl extends AccessibilityServiceInfoStubImpl { @Override public boolean getCanRetrieveWindowContent(AccessibilityServiceInfo info) { return AccessibilityServiceInfoCompatIcs.getCanRetrieveWindowContent(info); } @Override public String getDescription(AccessibilityServiceInfo info) { return AccessibilityServiceInfoCompatIcs.getDescription(info); } @Override public String getId(AccessibilityServiceInfo info) { return AccessibilityServiceInfoCompatIcs.getId(info); } @Override public ResolveInfo getResolveInfo(AccessibilityServiceInfo info) { return AccessibilityServiceInfoCompatIcs.getResolveInfo(info); } @Override public String getSettingsActivityName(AccessibilityServiceInfo info) { return AccessibilityServiceInfoCompatIcs.getSettingsActivityName(info); } @Override public int getCapabilities(AccessibilityServiceInfo info) { if (getCanRetrieveWindowContent(info)) { return CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT; } return 0; } } static class AccessibilityServiceInfoJellyBeanMr2 extends AccessibilityServiceInfoIcsImpl { @Override public int getCapabilities(AccessibilityServiceInfo info) { return AccessibilityServiceInfoCompatJellyBeanMr2.getCapabilities(info); } } static { if (Build.VERSION.SDK_INT >= 18) { // JellyBean MR2 IMPL = new AccessibilityServiceInfoJellyBeanMr2(); } else if (Build.VERSION.SDK_INT >= 14) { // ICS IMPL = new AccessibilityServiceInfoIcsImpl(); } else { IMPL = new AccessibilityServiceInfoStubImpl(); } } // Capabilities private static final AccessibilityServiceInfoVersionImpl IMPL; /** * 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 filter the key event stream. */ public static final int CAPABILITY_CAN_FILTER_KEY_EVENTS = 0x00000008; // Feedback types /** * Denotes braille feedback. */ public static final int FEEDBACK_BRAILLE = 0x0000020; /** * Mask for all feedback types. * * @see AccessibilityServiceInfo#FEEDBACK_SPOKEN * @see AccessibilityServiceInfo#FEEDBACK_HAPTIC * @see AccessibilityServiceInfo#FEEDBACK_AUDIBLE * @see AccessibilityServiceInfo#FEEDBACK_VISUAL * @see AccessibilityServiceInfo#FEEDBACK_GENERIC * @see FEEDBACK_BRAILLE */ public static final int FEEDBACK_ALL_MASK = 0xFFFFFFFF; // Flags /** * If an {@link AccessibilityService} is the default for a given type. * Default service is invoked only if no package specific one exists. In case of * more than one package specific service only the earlier registered is notified. */ public static final int DEFAULT = 0x0000001; /** * If this flag is set the system will regard views that are not important * for accessibility in addition to the ones that are important for accessibility. * That is, views that are marked as not important for accessibility via * {@link View#IMPORTANT_FOR_ACCESSIBILITY_NO} or * {@link View#IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS} and views that are * marked as potentially important for accessibility via * {@link View#IMPORTANT_FOR_ACCESSIBILITY_AUTO} for which the system has determined * that are not important for accessibility, are both reported while querying the * window content and also the accessibility service will receive accessibility events * from them. *

* Note: For accessibility services targeting API version * {@link Build.VERSION_CODES#JELLY_BEAN} or higher this flag has to be explicitly * set for the system to regard views that are not important for accessibility. For * accessibility services targeting API version lower than * {@link Build.VERSION_CODES#JELLY_BEAN} this flag is ignored and all views are * regarded for accessibility purposes. *

*

* Usually views not important for accessibility are layout managers that do not * react to user actions, do not draw any content, and do not have any special * semantics in the context of the screen content. For example, a three by three * grid can be implemented as three horizontal linear layouts and one vertical, * or three vertical linear layouts and one horizontal, or one grid layout, etc. * In this context the actual layout mangers used to achieve the grid configuration * are not important, rather it is important that there are nine evenly distributed * elements. *

*/ public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x0000002; /** * This flag requests that the system gets into touch exploration mode. * In this mode a single finger moving on the screen behaves as a mouse * pointer hovering over the user interface. The system will also detect * certain gestures performed on the touch screen and notify this service. * The system will enable touch exploration mode if there is at least one * accessibility service that has this flag set. Hence, clearing this * flag does not guarantee that the device will not be in touch exploration * mode since there may be another enabled service that requested it. *

* For accessibility services targeting API version higher than * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} that want to set * this flag have to declare this capability in their meta-data by setting * the attribute 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}. *

*

* Services targeting API version equal to or lower than * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} will work normally, i.e. * the first time they are run, if this flag is specified, a dialog is * shown to the user to confirm enabling explore by touch. *

*/ public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 0x0000004; /** * This flag requests from the system to enable web accessibility enhancing * extensions. Such extensions aim to provide improved accessibility support * for content presented in a {@link android.webkit.WebView}. An example of such * an extension is injecting JavaScript from a secure source. The system will enable * enhanced web accessibility if there is at least one accessibility service * that has this flag set. Hence, clearing this flag does not guarantee that the * device will not have enhanced web accessibility enabled since there may be * another enabled service that requested it. *

* Services that want to set this flag have to declare this capability * in their meta-data by setting the attribute 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}. *

*/ public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000008; /** * This flag requests that the AccessibilityNodeInfos obtained * by an {@link AccessibilityService} contain the id of the source view. * The source view id will be a fully qualified resource name of the * form "package:id/name", for example "foo.bar:id/my_list", and it is * useful for UI test automation. This flag is not set by default. */ 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. *

* Services that want to set this flag have to declare this capability * in their meta-data by setting the attribute 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}. *

*/ public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 0x00000020; /* * Hide constructor */ private AccessibilityServiceInfoCompat() {} /** * The accessibility service id. *

* Generated by the system. *

* * @return The id. */ public static String getId(AccessibilityServiceInfo info) { return IMPL.getId(info); } /** * The service {@link ResolveInfo}. *

* Generated by the system. *

* * @return The info. */ public static ResolveInfo getResolveInfo(AccessibilityServiceInfo info) { return IMPL.getResolveInfo(info); } /** * The settings activity name. *

* Statically set from {@link AccessibilityService#SERVICE_META_DATA * meta-data}. *

* * @return The settings activity name. */ public static String getSettingsActivityName(AccessibilityServiceInfo info) { return IMPL.getSettingsActivityName(info); } /** * Whether this service can retrieve the current window's content. *

* Statically set from {@link AccessibilityService#SERVICE_META_DATA * meta-data}. *

* * @return True window content can be retrieved. */ public static boolean getCanRetrieveWindowContent(AccessibilityServiceInfo info) { return IMPL.getCanRetrieveWindowContent(info); } /** * Description of the accessibility service. *

* Statically set from {@link AccessibilityService#SERVICE_META_DATA * meta-data}. *

* * @return The description. */ public static String getDescription(AccessibilityServiceInfo info) { return IMPL.getDescription(info); } /** * Returns the string representation of a feedback type. For example, * {@link AccessibilityServiceInfo#FEEDBACK_SPOKEN} is represented by the * string FEEDBACK_SPOKEN. * * @param feedbackType The feedback type. * @return The string representation. */ public static String feedbackTypeToString(int feedbackType) { StringBuilder builder = new StringBuilder(); builder.append("["); while (feedbackType > 0) { final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType); feedbackType &= ~feedbackTypeFlag; if (builder.length() > 1) { builder.append(", "); } switch (feedbackTypeFlag) { case AccessibilityServiceInfo.FEEDBACK_AUDIBLE: builder.append("FEEDBACK_AUDIBLE"); break; case AccessibilityServiceInfo.FEEDBACK_HAPTIC: builder.append("FEEDBACK_HAPTIC"); break; case AccessibilityServiceInfo.FEEDBACK_GENERIC: builder.append("FEEDBACK_GENERIC"); break; case AccessibilityServiceInfo.FEEDBACK_SPOKEN: builder.append("FEEDBACK_SPOKEN"); break; case AccessibilityServiceInfo.FEEDBACK_VISUAL: builder.append("FEEDBACK_VISUAL"); break; } } builder.append("]"); return builder.toString(); } /** * Returns the string representation of a flag. For example, * {@link AccessibilityServiceInfo#DEFAULT} is represented by the * string DEFAULT. * * @param flag The flag. * @return The string representation. */ public static String flagToString(int flag) { switch (flag) { case DEFAULT: return "DEFAULT"; case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS: 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 bit mask of capabilities this accessibility service has such as * being able to retrieve the active window content, etc. * * @param info The service info whose capabilities to get. * @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_CAN_FILTER_KEY_EVENTS */ public static int getCapabilities(AccessibilityServiceInfo info) { return IMPL.getCapabilities(info); } /** * 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_FILTER_KEY_EVENTS: return "CAPABILITY_CAN_FILTER_KEY_EVENTS"; default: return "UNKNOWN"; } } }