Home | History | Annotate | Download | only in accessibilityservice
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.accessibilityservice;
     18 
     19 import android.accessibilityservice.GestureDescription.MotionEventGenerator;
     20 import android.annotation.IntDef;
     21 import android.annotation.NonNull;
     22 import android.annotation.Nullable;
     23 import android.app.Service;
     24 import android.content.Context;
     25 import android.content.Intent;
     26 import android.content.pm.ParceledListSlice;
     27 import android.graphics.Region;
     28 import android.os.Handler;
     29 import android.os.IBinder;
     30 import android.os.Looper;
     31 import android.os.Message;
     32 import android.os.RemoteException;
     33 import android.provider.Settings;
     34 import android.util.ArrayMap;
     35 import android.util.Log;
     36 import android.util.Pair;
     37 import android.util.Slog;
     38 import android.util.SparseArray;
     39 import android.view.KeyEvent;
     40 import android.view.MotionEvent;
     41 import android.view.WindowManager;
     42 import android.view.WindowManagerImpl;
     43 import android.view.accessibility.AccessibilityEvent;
     44 import android.view.accessibility.AccessibilityInteractionClient;
     45 import android.view.accessibility.AccessibilityNodeInfo;
     46 import android.view.accessibility.AccessibilityWindowInfo;
     47 
     48 import com.android.internal.os.HandlerCaller;
     49 import com.android.internal.os.SomeArgs;
     50 
     51 import java.lang.annotation.Retention;
     52 import java.lang.annotation.RetentionPolicy;
     53 import java.util.List;
     54 
     55 /**
     56  * Accessibility services are intended to assist users with disabilities in using
     57  * Android devices and apps. They run in the background and receive callbacks by the system
     58  * when {@link AccessibilityEvent}s are fired. Such events denote some state transition
     59  * in the user interface, for example, the focus has changed, a button has been clicked,
     60  * etc. Such a service can optionally request the capability for querying the content
     61  * of the active window. Development of an accessibility service requires extending this
     62  * class and implementing its abstract methods.
     63  *
     64  * <div class="special reference">
     65  * <h3>Developer Guides</h3>
     66  * <p>For more information about creating AccessibilityServices, read the
     67  * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
     68  * developer guide.</p>
     69  * </div>
     70  *
     71  * <h3>Lifecycle</h3>
     72  * <p>
     73  * The lifecycle of an accessibility service is managed exclusively by the system and
     74  * follows the established service life cycle. Starting an accessibility service is triggered
     75  * exclusively by the user explicitly turning the service on in device settings. After the system
     76  * binds to a service, it calls {@link AccessibilityService#onServiceConnected()}. This method can
     77  * be overriden by clients that want to perform post binding setup.
     78  * </p>
     79  * <p>
     80  * An accessibility service stops either when the user turns it off in device settings or when
     81  * it calls {@link AccessibilityService#disableSelf()}.
     82  * </p>
     83  * <h3>Declaration</h3>
     84  * <p>
     85  * An accessibility is declared as any other service in an AndroidManifest.xml, but it
     86  * must do two things:
     87  * <ul>
     88  *     <ol>
     89  *         Specify that it handles the "android.accessibilityservice.AccessibilityService"
     90  *         {@link android.content.Intent}.
     91  *     </ol>
     92  *     <ol>
     93  *         Request the {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to
     94  *         ensure that only the system can bind to it.
     95  *     </ol>
     96  * </ul>
     97  * If either of these items is missing, the system will ignore the accessibility service.
     98  * Following is an example declaration:
     99  * </p>
    100  * <pre> &lt;service android:name=".MyAccessibilityService"
    101  *         android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"&gt;
    102  *     &lt;intent-filter&gt;
    103  *         &lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;
    104  *     &lt;/intent-filter&gt;
    105  *     . . .
    106  * &lt;/service&gt;</pre>
    107  * <h3>Configuration</h3>
    108  * <p>
    109  * An accessibility service can be configured to receive specific types of accessibility events,
    110  * listen only to specific packages, get events from each type only once in a given time frame,
    111  * retrieve window content, specify a settings activity, etc.
    112  * </p>
    113  * <p>
    114  * There are two approaches for configuring an accessibility service:
    115  * </p>
    116  * <ul>
    117  * <li>
    118  * Providing a {@link #SERVICE_META_DATA meta-data} entry in the manifest when declaring
    119  * the service. A service declaration with a meta-data tag is presented below:
    120  * <pre> &lt;service android:name=".MyAccessibilityService"&gt;
    121  *     &lt;intent-filter&gt;
    122  *         &lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;
    123  *     &lt;/intent-filter&gt;
    124  *     &lt;meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibilityservice" /&gt;
    125  * &lt;/service&gt;</pre>
    126  * <p class="note">
    127  * <strong>Note:</strong> This approach enables setting all properties.
    128  * </p>
    129  * <p>
    130  * For more details refer to {@link #SERVICE_META_DATA} and
    131  * <code>&lt;{@link android.R.styleable#AccessibilityService accessibility-service}&gt;</code>.
    132  * </p>
    133  * </li>
    134  * <li>
    135  * Calling {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}. Note
    136  * that this method can be called any time to dynamically change the service configuration.
    137  * <p class="note">
    138  * <strong>Note:</strong> This approach enables setting only dynamically configurable properties:
    139  * {@link AccessibilityServiceInfo#eventTypes},
    140  * {@link AccessibilityServiceInfo#feedbackType},
    141  * {@link AccessibilityServiceInfo#flags},
    142  * {@link AccessibilityServiceInfo#notificationTimeout},
    143  * {@link AccessibilityServiceInfo#packageNames}
    144  * </p>
    145  * <p>
    146  * For more details refer to {@link AccessibilityServiceInfo}.
    147  * </p>
    148  * </li>
    149  * </ul>
    150  * <h3>Retrieving window content</h3>
    151  * <p>
    152  * A service can specify in its declaration that it can retrieve window
    153  * content which is represented as a tree of {@link AccessibilityWindowInfo} and
    154  * {@link AccessibilityNodeInfo} objects. Note that
    155  * declaring this capability requires that the service declares its configuration via
    156  * an XML resource referenced by {@link #SERVICE_META_DATA}.
    157  * </p>
    158  * <p>
    159  * Window content may be retrieved with
    160  * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()},
    161  * {@link AccessibilityService#findFocus(int)},
    162  * {@link AccessibilityService#getWindows()}, or
    163  * {@link AccessibilityService#getRootInActiveWindow()}.
    164  * </p>
    165  * <p class="note">
    166  * <strong>Note</strong> An accessibility service may have requested to be notified for
    167  * a subset of the event types, and thus be unaware when the node hierarchy has changed. It is also
    168  * possible for a node to contain outdated information because the window content may change at any
    169  * time.
    170  * </p>
    171  * <h3>Notification strategy</h3>
    172  * <p>
    173  * All accessibility services are notified of all events they have requested, regardless of their
    174  * feedback type.
    175  * </p>
    176  * <p class="note">
    177  * <strong>Note:</strong> The event notification timeout is useful to avoid propagating
    178  * events to the client too frequently since this is accomplished via an expensive
    179  * interprocess call. One can think of the timeout as a criteria to determine when
    180  * event generation has settled down.</p>
    181  * <h3>Event types</h3>
    182  * <ul>
    183  * <li>{@link AccessibilityEvent#TYPE_VIEW_CLICKED}</li>
    184  * <li>{@link AccessibilityEvent#TYPE_VIEW_LONG_CLICKED}</li>
    185  * <li>{@link AccessibilityEvent#TYPE_VIEW_FOCUSED}</li>
    186  * <li>{@link AccessibilityEvent#TYPE_VIEW_SELECTED}</li>
    187  * <li>{@link AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED}</li>
    188  * <li>{@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}</li>
    189  * <li>{@link AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED}</li>
    190  * <li>{@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START}</li>
    191  * <li>{@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END}</li>
    192  * <li>{@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}</li>
    193  * <li>{@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}</li>
    194  * <li>{@link AccessibilityEvent#TYPE_VIEW_SCROLLED}</li>
    195  * <li>{@link AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED}</li>
    196  * <li>{@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}</li>
    197  * <li>{@link AccessibilityEvent#TYPE_ANNOUNCEMENT}</li>
    198  * <li>{@link AccessibilityEvent#TYPE_GESTURE_DETECTION_START}</li>
    199  * <li>{@link AccessibilityEvent#TYPE_GESTURE_DETECTION_END}</li>
    200  * <li>{@link AccessibilityEvent#TYPE_TOUCH_INTERACTION_START}</li>
    201  * <li>{@link AccessibilityEvent#TYPE_TOUCH_INTERACTION_END}</li>
    202  * <li>{@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED}</li>
    203  * <li>{@link AccessibilityEvent#TYPE_WINDOWS_CHANGED}</li>
    204  * <li>{@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED}</li>
    205  * </ul>
    206  * <h3>Feedback types</h3>
    207  * <ul>
    208  * <li>{@link AccessibilityServiceInfo#FEEDBACK_AUDIBLE}</li>
    209  * <li>{@link AccessibilityServiceInfo#FEEDBACK_HAPTIC}</li>
    210  * <li>{@link AccessibilityServiceInfo#FEEDBACK_AUDIBLE}</li>
    211  * <li>{@link AccessibilityServiceInfo#FEEDBACK_VISUAL}</li>
    212  * <li>{@link AccessibilityServiceInfo#FEEDBACK_GENERIC}</li>
    213  * <li>{@link AccessibilityServiceInfo#FEEDBACK_BRAILLE}</li>
    214  * </ul>
    215  * @see AccessibilityEvent
    216  * @see AccessibilityServiceInfo
    217  * @see android.view.accessibility.AccessibilityManager
    218  */
    219 public abstract class AccessibilityService extends Service {
    220 
    221     /**
    222      * The user has performed a swipe up gesture on the touch screen.
    223      */
    224     public static final int GESTURE_SWIPE_UP = 1;
    225 
    226     /**
    227      * The user has performed a swipe down gesture on the touch screen.
    228      */
    229     public static final int GESTURE_SWIPE_DOWN = 2;
    230 
    231     /**
    232      * The user has performed a swipe left gesture on the touch screen.
    233      */
    234     public static final int GESTURE_SWIPE_LEFT = 3;
    235 
    236     /**
    237      * The user has performed a swipe right gesture on the touch screen.
    238      */
    239     public static final int GESTURE_SWIPE_RIGHT = 4;
    240 
    241     /**
    242      * The user has performed a swipe left and right gesture on the touch screen.
    243      */
    244     public static final int GESTURE_SWIPE_LEFT_AND_RIGHT = 5;
    245 
    246     /**
    247      * The user has performed a swipe right and left gesture on the touch screen.
    248      */
    249     public static final int GESTURE_SWIPE_RIGHT_AND_LEFT = 6;
    250 
    251     /**
    252      * The user has performed a swipe up and down gesture on the touch screen.
    253      */
    254     public static final int GESTURE_SWIPE_UP_AND_DOWN = 7;
    255 
    256     /**
    257      * The user has performed a swipe down and up gesture on the touch screen.
    258      */
    259     public static final int GESTURE_SWIPE_DOWN_AND_UP = 8;
    260 
    261     /**
    262      * The user has performed a left and up gesture on the touch screen.
    263      */
    264     public static final int GESTURE_SWIPE_LEFT_AND_UP = 9;
    265 
    266     /**
    267      * The user has performed a left and down gesture on the touch screen.
    268      */
    269     public static final int GESTURE_SWIPE_LEFT_AND_DOWN = 10;
    270 
    271     /**
    272      * The user has performed a right and up gesture on the touch screen.
    273      */
    274     public static final int GESTURE_SWIPE_RIGHT_AND_UP = 11;
    275 
    276     /**
    277      * The user has performed a right and down gesture on the touch screen.
    278      */
    279     public static final int GESTURE_SWIPE_RIGHT_AND_DOWN = 12;
    280 
    281     /**
    282      * The user has performed an up and left gesture on the touch screen.
    283      */
    284     public static final int GESTURE_SWIPE_UP_AND_LEFT = 13;
    285 
    286     /**
    287      * The user has performed an up and right gesture on the touch screen.
    288      */
    289     public static final int GESTURE_SWIPE_UP_AND_RIGHT = 14;
    290 
    291     /**
    292      * The user has performed an down and left gesture on the touch screen.
    293      */
    294     public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 15;
    295 
    296     /**
    297      * The user has performed an down and right gesture on the touch screen.
    298      */
    299     public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 16;
    300 
    301     /**
    302      * The {@link Intent} that must be declared as handled by the service.
    303      */
    304     public static final String SERVICE_INTERFACE =
    305         "android.accessibilityservice.AccessibilityService";
    306 
    307     /**
    308      * Name under which an AccessibilityService component publishes information
    309      * about itself. This meta-data must reference an XML resource containing an
    310      * <code>&lt;{@link android.R.styleable#AccessibilityService accessibility-service}&gt;</code>
    311      * tag. This is a a sample XML file configuring an accessibility service:
    312      * <pre> &lt;accessibility-service
    313      *     android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
    314      *     android:packageNames="foo.bar, foo.baz"
    315      *     android:accessibilityFeedbackType="feedbackSpoken"
    316      *     android:notificationTimeout="100"
    317      *     android:accessibilityFlags="flagDefault"
    318      *     android:settingsActivity="foo.bar.TestBackActivity"
    319      *     android:canRetrieveWindowContent="true"
    320      *     android:canRequestTouchExplorationMode="true"
    321      *     . . .
    322      * /&gt;</pre>
    323      */
    324     public static final String SERVICE_META_DATA = "android.accessibilityservice";
    325 
    326     /**
    327      * Action to go back.
    328      */
    329     public static final int GLOBAL_ACTION_BACK = 1;
    330 
    331     /**
    332      * Action to go home.
    333      */
    334     public static final int GLOBAL_ACTION_HOME = 2;
    335 
    336     /**
    337      * Action to toggle showing the overview of recent apps
    338      */
    339     public static final int GLOBAL_ACTION_RECENTS = 3;
    340 
    341     /**
    342      * Action to open the notifications.
    343      */
    344     public static final int GLOBAL_ACTION_NOTIFICATIONS = 4;
    345 
    346     /**
    347      * Action to open the quick settings.
    348      */
    349     public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5;
    350 
    351     /**
    352      * Action to open the power long-press dialog.
    353      */
    354     public static final int GLOBAL_ACTION_POWER_DIALOG = 6;
    355 
    356     /**
    357      * Action to toggle docking the current app's window
    358      */
    359     public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7;
    360 
    361     private static final String LOG_TAG = "AccessibilityService";
    362 
    363     /**
    364      * @hide
    365      */
    366     public interface Callbacks {
    367         public void onAccessibilityEvent(AccessibilityEvent event);
    368         public void onInterrupt();
    369         public void onServiceConnected();
    370         public void init(int connectionId, IBinder windowToken);
    371         public boolean onGesture(int gestureId);
    372         public boolean onKeyEvent(KeyEvent event);
    373         public void onMagnificationChanged(@NonNull Region region,
    374                 float scale, float centerX, float centerY);
    375         public void onSoftKeyboardShowModeChanged(int showMode);
    376         public void onPerformGestureResult(int sequence, boolean completedSuccessfully);
    377     }
    378 
    379     /**
    380      * Annotations for Soft Keyboard show modes so tools can catch invalid show modes.
    381      * @hide
    382      */
    383     @Retention(RetentionPolicy.SOURCE)
    384     @IntDef({SHOW_MODE_AUTO, SHOW_MODE_HIDDEN})
    385     public @interface SoftKeyboardShowMode {};
    386     public static final int SHOW_MODE_AUTO = 0;
    387     public static final int SHOW_MODE_HIDDEN = 1;
    388 
    389     private int mConnectionId;
    390 
    391     private AccessibilityServiceInfo mInfo;
    392 
    393     private IBinder mWindowToken;
    394 
    395     private WindowManager mWindowManager;
    396 
    397     private MagnificationController mMagnificationController;
    398     private SoftKeyboardController mSoftKeyboardController;
    399 
    400     private int mGestureStatusCallbackSequence;
    401 
    402     private SparseArray<GestureResultCallbackInfo> mGestureStatusCallbackInfos;
    403 
    404     private final Object mLock = new Object();
    405 
    406     /**
    407      * Callback for {@link android.view.accessibility.AccessibilityEvent}s.
    408      *
    409      * @param event The new event. This event is owned by the caller and cannot be used after
    410      * this method returns. Services wishing to use the event after this method returns should
    411      * make a copy.
    412      */
    413     public abstract void onAccessibilityEvent(AccessibilityEvent event);
    414 
    415     /**
    416      * Callback for interrupting the accessibility feedback.
    417      */
    418     public abstract void onInterrupt();
    419 
    420     /**
    421      * Dispatches service connection to internal components first, then the
    422      * client code.
    423      */
    424     private void dispatchServiceConnected() {
    425         if (mMagnificationController != null) {
    426             mMagnificationController.onServiceConnected();
    427         }
    428 
    429         // The client gets to handle service connection last, after we've set
    430         // up any state upon which their code may rely.
    431         onServiceConnected();
    432     }
    433 
    434     /**
    435      * This method is a part of the {@link AccessibilityService} lifecycle and is
    436      * called after the system has successfully bound to the service. If is
    437      * convenient to use this method for setting the {@link AccessibilityServiceInfo}.
    438      *
    439      * @see AccessibilityServiceInfo
    440      * @see #setServiceInfo(AccessibilityServiceInfo)
    441      */
    442     protected void onServiceConnected() {
    443 
    444     }
    445 
    446     /**
    447      * Called by the system when the user performs a specific gesture on the
    448      * touch screen.
    449      *
    450      * <strong>Note:</strong> To receive gestures an accessibility service must
    451      * request that the device is in touch exploration mode by setting the
    452      * {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE}
    453      * flag.
    454      *
    455      * @param gestureId The unique id of the performed gesture.
    456      *
    457      * @return Whether the gesture was handled.
    458      *
    459      * @see #GESTURE_SWIPE_UP
    460      * @see #GESTURE_SWIPE_UP_AND_LEFT
    461      * @see #GESTURE_SWIPE_UP_AND_DOWN
    462      * @see #GESTURE_SWIPE_UP_AND_RIGHT
    463      * @see #GESTURE_SWIPE_DOWN
    464      * @see #GESTURE_SWIPE_DOWN_AND_LEFT
    465      * @see #GESTURE_SWIPE_DOWN_AND_UP
    466      * @see #GESTURE_SWIPE_DOWN_AND_RIGHT
    467      * @see #GESTURE_SWIPE_LEFT
    468      * @see #GESTURE_SWIPE_LEFT_AND_UP
    469      * @see #GESTURE_SWIPE_LEFT_AND_RIGHT
    470      * @see #GESTURE_SWIPE_LEFT_AND_DOWN
    471      * @see #GESTURE_SWIPE_RIGHT
    472      * @see #GESTURE_SWIPE_RIGHT_AND_UP
    473      * @see #GESTURE_SWIPE_RIGHT_AND_LEFT
    474      * @see #GESTURE_SWIPE_RIGHT_AND_DOWN
    475      */
    476     protected boolean onGesture(int gestureId) {
    477         return false;
    478     }
    479 
    480     /**
    481      * Callback that allows an accessibility service to observe the key events
    482      * before they are passed to the rest of the system. This means that the events
    483      * are first delivered here before they are passed to the device policy, the
    484      * input method, or applications.
    485      * <p>
    486      * <strong>Note:</strong> It is important that key events are handled in such
    487      * a way that the event stream that would be passed to the rest of the system
    488      * is well-formed. For example, handling the down event but not the up event
    489      * and vice versa would generate an inconsistent event stream.
    490      * </p>
    491      * <p>
    492      * <strong>Note:</strong> The key events delivered in this method are copies
    493      * and modifying them will have no effect on the events that will be passed
    494      * to the system. This method is intended to perform purely filtering
    495      * functionality.
    496      * <p>
    497      *
    498      * @param event The event to be processed. This event is owned by the caller and cannot be used
    499      * after this method returns. Services wishing to use the event after this method returns should
    500      * make a copy.
    501      * @return If true then the event will be consumed and not delivered to
    502      *         applications, otherwise it will be delivered as usual.
    503      */
    504     protected boolean onKeyEvent(KeyEvent event) {
    505         return false;
    506     }
    507 
    508     /**
    509      * Gets the windows on the screen. This method returns only the windows
    510      * that a sighted user can interact with, as opposed to all windows.
    511      * For example, if there is a modal dialog shown and the user cannot touch
    512      * anything behind it, then only the modal window will be reported
    513      * (assuming it is the top one). For convenience the returned windows
    514      * are ordered in a descending layer order, which is the windows that
    515      * are higher in the Z-order are reported first. Since the user can always
    516      * interact with the window that has input focus by typing, the focused
    517      * window is always returned (even if covered by a modal window).
    518      * <p>
    519      * <strong>Note:</strong> In order to access the windows your service has
    520      * to declare the capability to retrieve window content by setting the
    521      * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
    522      * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
    523      * Also the service has to opt-in to retrieve the interactive windows by
    524      * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
    525      * flag.
    526      * </p>
    527      *
    528      * @return The windows if there are windows and the service is can retrieve
    529      *         them, otherwise an empty list.
    530      */
    531     public List<AccessibilityWindowInfo> getWindows() {
    532         return AccessibilityInteractionClient.getInstance().getWindows(mConnectionId);
    533     }
    534 
    535     /**
    536      * Gets the root node in the currently active window if this service
    537      * can retrieve window content. The active window is the one that the user
    538      * is currently touching or the window with input focus, if the user is not
    539      * touching any window.
    540      * <p>
    541      * The currently active window is defined as the window that most recently fired one
    542      * of the following events:
    543      * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
    544      * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
    545      * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}.
    546      * In other words, the last window shown that also has input focus.
    547      * </p>
    548      * <p>
    549      * <strong>Note:</strong> In order to access the root node your service has
    550      * to declare the capability to retrieve window content by setting the
    551      * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
    552      * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
    553      * </p>
    554      *
    555      * @return The root node if this service can retrieve window content.
    556      */
    557     public AccessibilityNodeInfo getRootInActiveWindow() {
    558         return AccessibilityInteractionClient.getInstance().getRootInActiveWindow(mConnectionId);
    559     }
    560 
    561     /**
    562      * Disables the service. After calling this method, the service will be disabled and settings
    563      * will show that it is turned off.
    564      */
    565     public final void disableSelf() {
    566         final IAccessibilityServiceConnection connection =
    567                 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
    568         if (connection != null) {
    569             try {
    570                 connection.disableSelf();
    571             } catch (RemoteException re) {
    572                 throw new RuntimeException(re);
    573             }
    574         }
    575     }
    576 
    577     /**
    578      * Returns the magnification controller, which may be used to query and
    579      * modify the state of display magnification.
    580      * <p>
    581      * <strong>Note:</strong> In order to control magnification, your service
    582      * must declare the capability by setting the
    583      * {@link android.R.styleable#AccessibilityService_canControlMagnification}
    584      * property in its meta-data. For more information, see
    585      * {@link #SERVICE_META_DATA}.
    586      *
    587      * @return the magnification controller
    588      */
    589     @NonNull
    590     public final MagnificationController getMagnificationController() {
    591         synchronized (mLock) {
    592             if (mMagnificationController == null) {
    593                 mMagnificationController = new MagnificationController(this, mLock);
    594             }
    595             return mMagnificationController;
    596         }
    597     }
    598 
    599     /**
    600      * Dispatch a gesture to the touch screen. Any gestures currently in progress, whether from
    601      * the user, this service, or another service, will be cancelled.
    602      * <p>
    603      * The gesture will be dispatched as if it were performed directly on the screen by a user, so
    604      * the events may be affected by features such as magnification and explore by touch.
    605      * </p>
    606      * <p>
    607      * <strong>Note:</strong> In order to dispatch gestures, your service
    608      * must declare the capability by setting the
    609      * {@link android.R.styleable#AccessibilityService_canPerformGestures}
    610      * property in its meta-data. For more information, see
    611      * {@link #SERVICE_META_DATA}.
    612      * </p>
    613      *
    614      * @param gesture The gesture to dispatch
    615      * @param callback The object to call back when the status of the gesture is known. If
    616      * {@code null}, no status is reported.
    617      * @param handler The handler on which to call back the {@code callback} object. If
    618      * {@code null}, the object is called back on the service's main thread.
    619      *
    620      * @return {@code true} if the gesture is dispatched, {@code false} if not.
    621      */
    622     public final boolean dispatchGesture(@NonNull GestureDescription gesture,
    623             @Nullable GestureResultCallback callback,
    624             @Nullable Handler handler) {
    625         final IAccessibilityServiceConnection connection =
    626                 AccessibilityInteractionClient.getInstance().getConnection(
    627                         mConnectionId);
    628         if (connection == null) {
    629             return false;
    630         }
    631         List<GestureDescription.GestureStep> steps =
    632                 MotionEventGenerator.getGestureStepsFromGestureDescription(gesture, 100);
    633         try {
    634             synchronized (mLock) {
    635                 mGestureStatusCallbackSequence++;
    636                 if (callback != null) {
    637                     if (mGestureStatusCallbackInfos == null) {
    638                         mGestureStatusCallbackInfos = new SparseArray<>();
    639                     }
    640                     GestureResultCallbackInfo callbackInfo = new GestureResultCallbackInfo(gesture,
    641                             callback, handler);
    642                     mGestureStatusCallbackInfos.put(mGestureStatusCallbackSequence, callbackInfo);
    643                 }
    644                 connection.sendGesture(mGestureStatusCallbackSequence,
    645                         new ParceledListSlice<>(steps));
    646             }
    647         } catch (RemoteException re) {
    648             throw new RuntimeException(re);
    649         }
    650         return true;
    651     }
    652 
    653     void onPerformGestureResult(int sequence, final boolean completedSuccessfully) {
    654         if (mGestureStatusCallbackInfos == null) {
    655             return;
    656         }
    657         GestureResultCallbackInfo callbackInfo;
    658         synchronized (mLock) {
    659             callbackInfo = mGestureStatusCallbackInfos.get(sequence);
    660         }
    661         final GestureResultCallbackInfo finalCallbackInfo = callbackInfo;
    662         if ((callbackInfo != null) && (callbackInfo.gestureDescription != null)
    663                 && (callbackInfo.callback != null)) {
    664             if (callbackInfo.handler != null) {
    665                 callbackInfo.handler.post(new Runnable() {
    666                     @Override
    667                     public void run() {
    668                         if (completedSuccessfully) {
    669                             finalCallbackInfo.callback
    670                                     .onCompleted(finalCallbackInfo.gestureDescription);
    671                         } else {
    672                             finalCallbackInfo.callback
    673                                     .onCancelled(finalCallbackInfo.gestureDescription);
    674                         }
    675                     }
    676                 });
    677                 return;
    678             }
    679             if (completedSuccessfully) {
    680                 callbackInfo.callback.onCompleted(callbackInfo.gestureDescription);
    681             } else {
    682                 callbackInfo.callback.onCancelled(callbackInfo.gestureDescription);
    683             }
    684         }
    685     }
    686 
    687     private void onMagnificationChanged(@NonNull Region region, float scale,
    688             float centerX, float centerY) {
    689         if (mMagnificationController != null) {
    690             mMagnificationController.dispatchMagnificationChanged(
    691                     region, scale, centerX, centerY);
    692         }
    693     }
    694 
    695     /**
    696      * Used to control and query the state of display magnification.
    697      */
    698     public static final class MagnificationController {
    699         private final AccessibilityService mService;
    700 
    701         /**
    702          * Map of listeners to their handlers. Lazily created when adding the
    703          * first magnification listener.
    704          */
    705         private ArrayMap<OnMagnificationChangedListener, Handler> mListeners;
    706         private final Object mLock;
    707 
    708         MagnificationController(@NonNull AccessibilityService service, @NonNull Object lock) {
    709             mService = service;
    710             mLock = lock;
    711         }
    712 
    713         /**
    714          * Called when the service is connected.
    715          */
    716         void onServiceConnected() {
    717             synchronized (mLock) {
    718                 if (mListeners != null && !mListeners.isEmpty()) {
    719                     setMagnificationCallbackEnabled(true);
    720                 }
    721             }
    722         }
    723 
    724         /**
    725          * Adds the specified change listener to the list of magnification
    726          * change listeners. The callback will occur on the service's main
    727          * thread.
    728          *
    729          * @param listener the listener to add, must be non-{@code null}
    730          */
    731         public void addListener(@NonNull OnMagnificationChangedListener listener) {
    732             addListener(listener, null);
    733         }
    734 
    735         /**
    736          * Adds the specified change listener to the list of magnification
    737          * change listeners. The callback will occur on the specified
    738          * {@link Handler}'s thread, or on the service's main thread if the
    739          * handler is {@code null}.
    740          *
    741          * @param listener the listener to add, must be non-null
    742          * @param handler the handler on which the callback should execute, or
    743          *        {@code null} to execute on the service's main thread
    744          */
    745         public void addListener(@NonNull OnMagnificationChangedListener listener,
    746                 @Nullable Handler handler) {
    747             synchronized (mLock) {
    748                 if (mListeners == null) {
    749                     mListeners = new ArrayMap<>();
    750                 }
    751 
    752                 final boolean shouldEnableCallback = mListeners.isEmpty();
    753                 mListeners.put(listener, handler);
    754 
    755                 if (shouldEnableCallback) {
    756                     // This may fail if the service is not connected yet, but if we
    757                     // still have listeners when it connects then we can try again.
    758                     setMagnificationCallbackEnabled(true);
    759                 }
    760             }
    761         }
    762 
    763         /**
    764          * Removes all instances of the specified change listener from the list
    765          * of magnification change listeners.
    766          *
    767          * @param listener the listener to remove, must be non-null
    768          * @return {@code true} if at least one instance of the listener was
    769          *         removed
    770          */
    771         public boolean removeListener(@NonNull OnMagnificationChangedListener listener) {
    772             if (mListeners == null) {
    773                 return false;
    774             }
    775 
    776             synchronized (mLock) {
    777                 final int keyIndex = mListeners.indexOfKey(listener);
    778                 final boolean hasKey = keyIndex >= 0;
    779                 if (hasKey) {
    780                     mListeners.removeAt(keyIndex);
    781                 }
    782 
    783                 if (hasKey && mListeners.isEmpty()) {
    784                     // We just removed the last listener, so we don't need
    785                     // callbacks from the service anymore.
    786                     setMagnificationCallbackEnabled(false);
    787                 }
    788 
    789                 return hasKey;
    790             }
    791         }
    792 
    793         private void setMagnificationCallbackEnabled(boolean enabled) {
    794             final IAccessibilityServiceConnection connection =
    795                     AccessibilityInteractionClient.getInstance().getConnection(
    796                             mService.mConnectionId);
    797             if (connection != null) {
    798                 try {
    799                     connection.setMagnificationCallbackEnabled(enabled);
    800                 } catch (RemoteException re) {
    801                     throw new RuntimeException(re);
    802                 }
    803             }
    804         }
    805 
    806         /**
    807          * Dispatches magnification changes to any registered listeners. This
    808          * should be called on the service's main thread.
    809          */
    810         void dispatchMagnificationChanged(final @NonNull Region region, final float scale,
    811                 final float centerX, final float centerY) {
    812             final ArrayMap<OnMagnificationChangedListener, Handler> entries;
    813             synchronized (mLock) {
    814                 if (mListeners == null || mListeners.isEmpty()) {
    815                     Slog.d(LOG_TAG, "Received magnification changed "
    816                             + "callback with no listeners registered!");
    817                     setMagnificationCallbackEnabled(false);
    818                     return;
    819                 }
    820 
    821                 // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
    822                 // modification.
    823                 entries = new ArrayMap<>(mListeners);
    824             }
    825 
    826             for (int i = 0, count = entries.size(); i < count; i++) {
    827                 final OnMagnificationChangedListener listener = entries.keyAt(i);
    828                 final Handler handler = entries.valueAt(i);
    829                 if (handler != null) {
    830                     handler.post(new Runnable() {
    831                         @Override
    832                         public void run() {
    833                             listener.onMagnificationChanged(MagnificationController.this,
    834                                     region, scale, centerX, centerY);
    835                         }
    836                     });
    837                 } else {
    838                     // We're already on the main thread, just run the listener.
    839                     listener.onMagnificationChanged(this, region, scale, centerX, centerY);
    840                 }
    841             }
    842         }
    843 
    844         /**
    845          * Returns the current magnification scale.
    846          * <p>
    847          * <strong>Note:</strong> If the service is not yet connected (e.g.
    848          * {@link AccessibilityService#onServiceConnected()} has not yet been
    849          * called) or the service has been disconnected, this method will
    850          * return a default value of {@code 1.0f}.
    851          *
    852          * @return the current magnification scale
    853          */
    854         public float getScale() {
    855             final IAccessibilityServiceConnection connection =
    856                     AccessibilityInteractionClient.getInstance().getConnection(
    857                             mService.mConnectionId);
    858             if (connection != null) {
    859                 try {
    860                     return connection.getMagnificationScale();
    861                 } catch (RemoteException re) {
    862                     Log.w(LOG_TAG, "Failed to obtain scale", re);
    863                     re.rethrowFromSystemServer();
    864                 }
    865             }
    866             return 1.0f;
    867         }
    868 
    869         /**
    870          * Returns the unscaled screen-relative X coordinate of the focal
    871          * center of the magnified region. This is the point around which
    872          * zooming occurs and is guaranteed to lie within the magnified
    873          * region.
    874          * <p>
    875          * <strong>Note:</strong> If the service is not yet connected (e.g.
    876          * {@link AccessibilityService#onServiceConnected()} has not yet been
    877          * called) or the service has been disconnected, this method will
    878          * return a default value of {@code 0.0f}.
    879          *
    880          * @return the unscaled screen-relative X coordinate of the center of
    881          *         the magnified region
    882          */
    883         public float getCenterX() {
    884             final IAccessibilityServiceConnection connection =
    885                     AccessibilityInteractionClient.getInstance().getConnection(
    886                             mService.mConnectionId);
    887             if (connection != null) {
    888                 try {
    889                     return connection.getMagnificationCenterX();
    890                 } catch (RemoteException re) {
    891                     Log.w(LOG_TAG, "Failed to obtain center X", re);
    892                     re.rethrowFromSystemServer();
    893                 }
    894             }
    895             return 0.0f;
    896         }
    897 
    898         /**
    899          * Returns the unscaled screen-relative Y coordinate of the focal
    900          * center of the magnified region. This is the point around which
    901          * zooming occurs and is guaranteed to lie within the magnified
    902          * region.
    903          * <p>
    904          * <strong>Note:</strong> If the service is not yet connected (e.g.
    905          * {@link AccessibilityService#onServiceConnected()} has not yet been
    906          * called) or the service has been disconnected, this method will
    907          * return a default value of {@code 0.0f}.
    908          *
    909          * @return the unscaled screen-relative Y coordinate of the center of
    910          *         the magnified region
    911          */
    912         public float getCenterY() {
    913             final IAccessibilityServiceConnection connection =
    914                     AccessibilityInteractionClient.getInstance().getConnection(
    915                             mService.mConnectionId);
    916             if (connection != null) {
    917                 try {
    918                     return connection.getMagnificationCenterY();
    919                 } catch (RemoteException re) {
    920                     Log.w(LOG_TAG, "Failed to obtain center Y", re);
    921                     re.rethrowFromSystemServer();
    922                 }
    923             }
    924             return 0.0f;
    925         }
    926 
    927         /**
    928          * Returns the region of the screen currently active for magnification. Changes to
    929          * magnification scale and center only affect this portion of the screen. The rest of the
    930          * screen, for example input methods, cannot be magnified. This region is relative to the
    931          * unscaled screen and is independent of the scale and center point.
    932          * <p>
    933          * The returned region will be empty if magnification is not active. Magnification is active
    934          * if magnification gestures are enabled or if a service is running that can control
    935          * magnification.
    936          * <p>
    937          * <strong>Note:</strong> If the service is not yet connected (e.g.
    938          * {@link AccessibilityService#onServiceConnected()} has not yet been
    939          * called) or the service has been disconnected, this method will
    940          * return an empty region.
    941          *
    942          * @return the region of the screen currently active for magnification, or an empty region
    943          * if magnification is not active.
    944          */
    945         @NonNull
    946         public Region getMagnificationRegion() {
    947             final IAccessibilityServiceConnection connection =
    948                     AccessibilityInteractionClient.getInstance().getConnection(
    949                             mService.mConnectionId);
    950             if (connection != null) {
    951                 try {
    952                     return connection.getMagnificationRegion();
    953                 } catch (RemoteException re) {
    954                     Log.w(LOG_TAG, "Failed to obtain magnified region", re);
    955                     re.rethrowFromSystemServer();
    956                 }
    957             }
    958             return Region.obtain();
    959         }
    960 
    961         /**
    962          * Resets magnification scale and center to their default (e.g. no
    963          * magnification) values.
    964          * <p>
    965          * <strong>Note:</strong> If the service is not yet connected (e.g.
    966          * {@link AccessibilityService#onServiceConnected()} has not yet been
    967          * called) or the service has been disconnected, this method will have
    968          * no effect and return {@code false}.
    969          *
    970          * @param animate {@code true} to animate from the current scale and
    971          *                center or {@code false} to reset the scale and center
    972          *                immediately
    973          * @return {@code true} on success, {@code false} on failure
    974          */
    975         public boolean reset(boolean animate) {
    976             final IAccessibilityServiceConnection connection =
    977                     AccessibilityInteractionClient.getInstance().getConnection(
    978                             mService.mConnectionId);
    979             if (connection != null) {
    980                 try {
    981                     return connection.resetMagnification(animate);
    982                 } catch (RemoteException re) {
    983                     Log.w(LOG_TAG, "Failed to reset", re);
    984                     re.rethrowFromSystemServer();
    985                 }
    986             }
    987             return false;
    988         }
    989 
    990         /**
    991          * Sets the magnification scale.
    992          * <p>
    993          * <strong>Note:</strong> If the service is not yet connected (e.g.
    994          * {@link AccessibilityService#onServiceConnected()} has not yet been
    995          * called) or the service has been disconnected, this method will have
    996          * no effect and return {@code false}.
    997          *
    998          * @param scale the magnification scale to set, must be >= 1 and <= 5
    999          * @param animate {@code true} to animate from the current scale or
   1000          *                {@code false} to set the scale immediately
   1001          * @return {@code true} on success, {@code false} on failure
   1002          */
   1003         public boolean setScale(float scale, boolean animate) {
   1004             final IAccessibilityServiceConnection connection =
   1005                     AccessibilityInteractionClient.getInstance().getConnection(
   1006                             mService.mConnectionId);
   1007             if (connection != null) {
   1008                 try {
   1009                     return connection.setMagnificationScaleAndCenter(
   1010                             scale, Float.NaN, Float.NaN, animate);
   1011                 } catch (RemoteException re) {
   1012                     Log.w(LOG_TAG, "Failed to set scale", re);
   1013                     re.rethrowFromSystemServer();
   1014                 }
   1015             }
   1016             return false;
   1017         }
   1018 
   1019         /**
   1020          * Sets the center of the magnified viewport.
   1021          * <p>
   1022          * <strong>Note:</strong> If the service is not yet connected (e.g.
   1023          * {@link AccessibilityService#onServiceConnected()} has not yet been
   1024          * called) or the service has been disconnected, this method will have
   1025          * no effect and return {@code false}.
   1026          *
   1027          * @param centerX the unscaled screen-relative X coordinate on which to
   1028          *                center the viewport
   1029          * @param centerY the unscaled screen-relative Y coordinate on which to
   1030          *                center the viewport
   1031          * @param animate {@code true} to animate from the current viewport
   1032          *                center or {@code false} to set the center immediately
   1033          * @return {@code true} on success, {@code false} on failure
   1034          */
   1035         public boolean setCenter(float centerX, float centerY, boolean animate) {
   1036             final IAccessibilityServiceConnection connection =
   1037                     AccessibilityInteractionClient.getInstance().getConnection(
   1038                             mService.mConnectionId);
   1039             if (connection != null) {
   1040                 try {
   1041                     return connection.setMagnificationScaleAndCenter(
   1042                             Float.NaN, centerX, centerY, animate);
   1043                 } catch (RemoteException re) {
   1044                     Log.w(LOG_TAG, "Failed to set center", re);
   1045                     re.rethrowFromSystemServer();
   1046                 }
   1047             }
   1048             return false;
   1049         }
   1050 
   1051         /**
   1052          * Listener for changes in the state of magnification.
   1053          */
   1054         public interface OnMagnificationChangedListener {
   1055             /**
   1056              * Called when the magnified region, scale, or center changes.
   1057              *
   1058              * @param controller the magnification controller
   1059              * @param region the magnification region
   1060              * @param scale the new scale
   1061              * @param centerX the new X coordinate, in unscaled coordinates, around which
   1062              * magnification is focused
   1063              * @param centerY the new Y coordinate, in unscaled coordinates, around which
   1064              * magnification is focused
   1065              */
   1066             void onMagnificationChanged(@NonNull MagnificationController controller,
   1067                     @NonNull Region region, float scale, float centerX, float centerY);
   1068         }
   1069     }
   1070 
   1071     /**
   1072      * Returns the soft keyboard controller, which may be used to query and modify the soft keyboard
   1073      * show mode.
   1074      *
   1075      * @return the soft keyboard controller
   1076      */
   1077     @NonNull
   1078     public final SoftKeyboardController getSoftKeyboardController() {
   1079         synchronized (mLock) {
   1080             if (mSoftKeyboardController == null) {
   1081                 mSoftKeyboardController = new SoftKeyboardController(this, mLock);
   1082             }
   1083             return mSoftKeyboardController;
   1084         }
   1085     }
   1086 
   1087     private void onSoftKeyboardShowModeChanged(int showMode) {
   1088         if (mSoftKeyboardController != null) {
   1089             mSoftKeyboardController.dispatchSoftKeyboardShowModeChanged(showMode);
   1090         }
   1091     }
   1092 
   1093     /**
   1094      * Used to control and query the soft keyboard show mode.
   1095      */
   1096     public static final class SoftKeyboardController {
   1097         private final AccessibilityService mService;
   1098 
   1099         /**
   1100          * Map of listeners to their handlers. Lazily created when adding the first
   1101          * soft keyboard change listener.
   1102          */
   1103         private ArrayMap<OnShowModeChangedListener, Handler> mListeners;
   1104         private final Object mLock;
   1105 
   1106         SoftKeyboardController(@NonNull AccessibilityService service, @NonNull Object lock) {
   1107             mService = service;
   1108             mLock = lock;
   1109         }
   1110 
   1111         /**
   1112          * Called when the service is connected.
   1113          */
   1114         void onServiceConnected() {
   1115             synchronized(mLock) {
   1116                 if (mListeners != null && !mListeners.isEmpty()) {
   1117                     setSoftKeyboardCallbackEnabled(true);
   1118                 }
   1119             }
   1120         }
   1121 
   1122         /**
   1123          * Adds the specified change listener to the list of show mode change listeners. The
   1124          * callback will occur on the service's main thread. Listener is not called on registration.
   1125          */
   1126         public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) {
   1127             addOnShowModeChangedListener(listener, null);
   1128         }
   1129 
   1130         /**
   1131          * Adds the specified change listener to the list of soft keyboard show mode change
   1132          * listeners. The callback will occur on the specified {@link Handler}'s thread, or on the
   1133          * services's main thread if the handler is {@code null}.
   1134          *
   1135          * @param listener the listener to add, must be non-null
   1136          * @param handler the handler on which to callback should execute, or {@code null} to
   1137          *        execute on the service's main thread
   1138          */
   1139         public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener,
   1140                 @Nullable Handler handler) {
   1141             synchronized (mLock) {
   1142                 if (mListeners == null) {
   1143                     mListeners = new ArrayMap<>();
   1144                 }
   1145 
   1146                 final boolean shouldEnableCallback = mListeners.isEmpty();
   1147                 mListeners.put(listener, handler);
   1148 
   1149                 if (shouldEnableCallback) {
   1150                     // This may fail if the service is not connected yet, but if we still have
   1151                     // listeners when it connects, we can try again.
   1152                     setSoftKeyboardCallbackEnabled(true);
   1153                 }
   1154             }
   1155         }
   1156 
   1157         /**
   1158          * Removes all instances of the specified change listener from the list of magnification
   1159          * change listeners.
   1160          *
   1161          * @param listener the listener to remove, must be non-null
   1162          * @return {@code true} if at least one instance of the listener was removed
   1163          */
   1164         public boolean removeOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) {
   1165             if (mListeners == null) {
   1166                 return false;
   1167             }
   1168 
   1169             synchronized (mLock) {
   1170                 final int keyIndex = mListeners.indexOfKey(listener);
   1171                 final boolean hasKey = keyIndex >= 0;
   1172                 if (hasKey) {
   1173                     mListeners.removeAt(keyIndex);
   1174                 }
   1175 
   1176                 if (hasKey && mListeners.isEmpty()) {
   1177                     // We just removed the last listener, so we don't need callbacks from the
   1178                     // service anymore.
   1179                     setSoftKeyboardCallbackEnabled(false);
   1180                 }
   1181 
   1182                 return hasKey;
   1183             }
   1184         }
   1185 
   1186         private void setSoftKeyboardCallbackEnabled(boolean enabled) {
   1187             final IAccessibilityServiceConnection connection =
   1188                     AccessibilityInteractionClient.getInstance().getConnection(
   1189                             mService.mConnectionId);
   1190             if (connection != null) {
   1191                 try {
   1192                     connection.setSoftKeyboardCallbackEnabled(enabled);
   1193                 } catch (RemoteException re) {
   1194                     throw new RuntimeException(re);
   1195                 }
   1196             }
   1197         }
   1198 
   1199         /**
   1200          * Dispatches the soft keyboard show mode change to any registered listeners. This should
   1201          * be called on the service's main thread.
   1202          */
   1203         void dispatchSoftKeyboardShowModeChanged(final int showMode) {
   1204             final ArrayMap<OnShowModeChangedListener, Handler> entries;
   1205             synchronized (mLock) {
   1206                 if (mListeners == null || mListeners.isEmpty()) {
   1207                     Slog.d(LOG_TAG, "Received soft keyboard show mode changed callback"
   1208                             + " with no listeners registered!");
   1209                     setSoftKeyboardCallbackEnabled(false);
   1210                     return;
   1211                 }
   1212 
   1213                 // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
   1214                 // modification.
   1215                 entries = new ArrayMap<>(mListeners);
   1216             }
   1217 
   1218             for (int i = 0, count = entries.size(); i < count; i++) {
   1219                 final OnShowModeChangedListener listener = entries.keyAt(i);
   1220                 final Handler handler = entries.valueAt(i);
   1221                 if (handler != null) {
   1222                     handler.post(new Runnable() {
   1223                         @Override
   1224                         public void run() {
   1225                             listener.onShowModeChanged(SoftKeyboardController.this, showMode);
   1226                         }
   1227                     });
   1228                 } else {
   1229                     // We're already on the main thread, just run the listener.
   1230                     listener.onShowModeChanged(this, showMode);
   1231                 }
   1232             }
   1233         }
   1234 
   1235         /**
   1236          * Returns the show mode of the soft keyboard. The default show mode is
   1237          * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is
   1238          * focused. An AccessibilityService can also request the show mode
   1239          * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
   1240          *
   1241          * @return the current soft keyboard show mode
   1242          */
   1243         @SoftKeyboardShowMode
   1244         public int getShowMode() {
   1245            try {
   1246                return Settings.Secure.getInt(mService.getContentResolver(),
   1247                        Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
   1248            } catch (Settings.SettingNotFoundException e) {
   1249                Log.v(LOG_TAG, "Failed to obtain the soft keyboard mode", e);
   1250                // The settings hasn't been changed yet, so it's value is null. Return the default.
   1251                return 0;
   1252            }
   1253         }
   1254 
   1255         /**
   1256          * Sets the soft keyboard show mode. The default show mode is
   1257          * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is
   1258          * focused. An AccessibilityService can also request the show mode
   1259          * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown. The
   1260          * The lastto this method will be honored, regardless of any previous calls (including those
   1261          * made by other AccessibilityServices).
   1262          * <p>
   1263          * <strong>Note:</strong> If the service is not yet conected (e.g.
   1264          * {@link AccessibilityService#onServiceConnected()} has not yet been called) or the
   1265          * service has been disconnected, this method will hav no effect and return {@code false}.
   1266          *
   1267          * @param showMode the new show mode for the soft keyboard
   1268          * @return {@code true} on success
   1269          */
   1270         public boolean setShowMode(@SoftKeyboardShowMode int showMode) {
   1271            final IAccessibilityServiceConnection connection =
   1272                    AccessibilityInteractionClient.getInstance().getConnection(
   1273                            mService.mConnectionId);
   1274            if (connection != null) {
   1275                try {
   1276                    return connection.setSoftKeyboardShowMode(showMode);
   1277                } catch (RemoteException re) {
   1278                    Log.w(LOG_TAG, "Failed to set soft keyboard behavior", re);
   1279                    re.rethrowFromSystemServer();
   1280                }
   1281            }
   1282            return false;
   1283         }
   1284 
   1285         /**
   1286          * Listener for changes in the soft keyboard show mode.
   1287          */
   1288         public interface OnShowModeChangedListener {
   1289            /**
   1290             * Called when the soft keyboard behavior changes. The default show mode is
   1291             * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is
   1292             * focused. An AccessibilityService can also request the show mode
   1293             * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
   1294             *
   1295             * @param controller the soft keyboard controller
   1296             * @param showMode the current soft keyboard show mode
   1297             */
   1298             void onShowModeChanged(@NonNull SoftKeyboardController controller,
   1299                     @SoftKeyboardShowMode int showMode);
   1300         }
   1301     }
   1302 
   1303     /**
   1304      * Performs a global action. Such an action can be performed
   1305      * at any moment regardless of the current application or user
   1306      * location in that application. For example going back, going
   1307      * home, opening recents, etc.
   1308      *
   1309      * @param action The action to perform.
   1310      * @return Whether the action was successfully performed.
   1311      *
   1312      * @see #GLOBAL_ACTION_BACK
   1313      * @see #GLOBAL_ACTION_HOME
   1314      * @see #GLOBAL_ACTION_NOTIFICATIONS
   1315      * @see #GLOBAL_ACTION_RECENTS
   1316      */
   1317     public final boolean performGlobalAction(int action) {
   1318         IAccessibilityServiceConnection connection =
   1319             AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
   1320         if (connection != null) {
   1321             try {
   1322                 return connection.performGlobalAction(action);
   1323             } catch (RemoteException re) {
   1324                 Log.w(LOG_TAG, "Error while calling performGlobalAction", re);
   1325                 re.rethrowFromSystemServer();
   1326             }
   1327         }
   1328         return false;
   1329     }
   1330 
   1331     /**
   1332      * Find the view that has the specified focus type. The search is performed
   1333      * across all windows.
   1334      * <p>
   1335      * <strong>Note:</strong> In order to access the windows your service has
   1336      * to declare the capability to retrieve window content by setting the
   1337      * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
   1338      * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
   1339      * Also the service has to opt-in to retrieve the interactive windows by
   1340      * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
   1341      * flag. Otherwise, the search will be performed only in the active window.
   1342      * </p>
   1343      *
   1344      * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
   1345      *         {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
   1346      * @return The node info of the focused view or null.
   1347      *
   1348      * @see AccessibilityNodeInfo#FOCUS_INPUT
   1349      * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY
   1350      */
   1351     public AccessibilityNodeInfo findFocus(int focus) {
   1352         return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId,
   1353                 AccessibilityNodeInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus);
   1354     }
   1355 
   1356     /**
   1357      * Gets the an {@link AccessibilityServiceInfo} describing this
   1358      * {@link AccessibilityService}. This method is useful if one wants
   1359      * to change some of the dynamically configurable properties at
   1360      * runtime.
   1361      *
   1362      * @return The accessibility service info.
   1363      *
   1364      * @see AccessibilityServiceInfo
   1365      */
   1366     public final AccessibilityServiceInfo getServiceInfo() {
   1367         IAccessibilityServiceConnection connection =
   1368             AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
   1369         if (connection != null) {
   1370             try {
   1371                 return connection.getServiceInfo();
   1372             } catch (RemoteException re) {
   1373                 Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re);
   1374                 re.rethrowFromSystemServer();
   1375             }
   1376         }
   1377         return null;
   1378     }
   1379 
   1380     /**
   1381      * Sets the {@link AccessibilityServiceInfo} that describes this service.
   1382      * <p>
   1383      * Note: You can call this method any time but the info will be picked up after
   1384      *       the system has bound to this service and when this method is called thereafter.
   1385      *
   1386      * @param info The info.
   1387      */
   1388     public final void setServiceInfo(AccessibilityServiceInfo info) {
   1389         mInfo = info;
   1390         sendServiceInfo();
   1391     }
   1392 
   1393     /**
   1394      * Sets the {@link AccessibilityServiceInfo} for this service if the latter is
   1395      * properly set and there is an {@link IAccessibilityServiceConnection} to the
   1396      * AccessibilityManagerService.
   1397      */
   1398     private void sendServiceInfo() {
   1399         IAccessibilityServiceConnection connection =
   1400             AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
   1401         if (mInfo != null && connection != null) {
   1402             try {
   1403                 connection.setServiceInfo(mInfo);
   1404                 mInfo = null;
   1405                 AccessibilityInteractionClient.getInstance().clearCache();
   1406             } catch (RemoteException re) {
   1407                 Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re);
   1408                 re.rethrowFromSystemServer();
   1409             }
   1410         }
   1411     }
   1412 
   1413     @Override
   1414     public Object getSystemService(@ServiceName @NonNull String name) {
   1415         if (getBaseContext() == null) {
   1416             throw new IllegalStateException(
   1417                     "System services not available to Activities before onCreate()");
   1418         }
   1419 
   1420         // Guarantee that we always return the same window manager instance.
   1421         if (WINDOW_SERVICE.equals(name)) {
   1422             if (mWindowManager == null) {
   1423                 mWindowManager = (WindowManager) getBaseContext().getSystemService(name);
   1424             }
   1425             return mWindowManager;
   1426         }
   1427         return super.getSystemService(name);
   1428     }
   1429 
   1430     /**
   1431      * Implement to return the implementation of the internal accessibility
   1432      * service interface.
   1433      */
   1434     @Override
   1435     public final IBinder onBind(Intent intent) {
   1436         return new IAccessibilityServiceClientWrapper(this, getMainLooper(), new Callbacks() {
   1437             @Override
   1438             public void onServiceConnected() {
   1439                 AccessibilityService.this.dispatchServiceConnected();
   1440             }
   1441 
   1442             @Override
   1443             public void onInterrupt() {
   1444                 AccessibilityService.this.onInterrupt();
   1445             }
   1446 
   1447             @Override
   1448             public void onAccessibilityEvent(AccessibilityEvent event) {
   1449                 AccessibilityService.this.onAccessibilityEvent(event);
   1450             }
   1451 
   1452             @Override
   1453             public void init(int connectionId, IBinder windowToken) {
   1454                 mConnectionId = connectionId;
   1455                 mWindowToken = windowToken;
   1456 
   1457                 // The client may have already obtained the window manager, so
   1458                 // update the default token on whatever manager we gave them.
   1459                 final WindowManagerImpl wm = (WindowManagerImpl) getSystemService(WINDOW_SERVICE);
   1460                 wm.setDefaultToken(windowToken);
   1461             }
   1462 
   1463             @Override
   1464             public boolean onGesture(int gestureId) {
   1465                 return AccessibilityService.this.onGesture(gestureId);
   1466             }
   1467 
   1468             @Override
   1469             public boolean onKeyEvent(KeyEvent event) {
   1470                 return AccessibilityService.this.onKeyEvent(event);
   1471             }
   1472 
   1473             @Override
   1474             public void onMagnificationChanged(@NonNull Region region,
   1475                     float scale, float centerX, float centerY) {
   1476                 AccessibilityService.this.onMagnificationChanged(region, scale, centerX, centerY);
   1477             }
   1478 
   1479             @Override
   1480             public void onSoftKeyboardShowModeChanged(int showMode) {
   1481                 AccessibilityService.this.onSoftKeyboardShowModeChanged(showMode);
   1482             }
   1483 
   1484             @Override
   1485             public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
   1486                 AccessibilityService.this.onPerformGestureResult(sequence, completedSuccessfully);
   1487             }
   1488         });
   1489     }
   1490 
   1491     /**
   1492      * Implements the internal {@link IAccessibilityServiceClient} interface to convert
   1493      * incoming calls to it back to calls on an {@link AccessibilityService}.
   1494      *
   1495      * @hide
   1496      */
   1497     public static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub
   1498             implements HandlerCaller.Callback {
   1499         private static final int DO_INIT = 1;
   1500         private static final int DO_ON_INTERRUPT = 2;
   1501         private static final int DO_ON_ACCESSIBILITY_EVENT = 3;
   1502         private static final int DO_ON_GESTURE = 4;
   1503         private static final int DO_CLEAR_ACCESSIBILITY_CACHE = 5;
   1504         private static final int DO_ON_KEY_EVENT = 6;
   1505         private static final int DO_ON_MAGNIFICATION_CHANGED = 7;
   1506         private static final int DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED = 8;
   1507         private static final int DO_GESTURE_COMPLETE = 9;
   1508 
   1509         private final HandlerCaller mCaller;
   1510 
   1511         private final Callbacks mCallback;
   1512 
   1513         private int mConnectionId;
   1514 
   1515         public IAccessibilityServiceClientWrapper(Context context, Looper looper,
   1516                 Callbacks callback) {
   1517             mCallback = callback;
   1518             mCaller = new HandlerCaller(context, looper, this, true /*asyncHandler*/);
   1519         }
   1520 
   1521         public void init(IAccessibilityServiceConnection connection, int connectionId,
   1522                 IBinder windowToken) {
   1523             Message message = mCaller.obtainMessageIOO(DO_INIT, connectionId,
   1524                     connection, windowToken);
   1525             mCaller.sendMessage(message);
   1526         }
   1527 
   1528         public void onInterrupt() {
   1529             Message message = mCaller.obtainMessage(DO_ON_INTERRUPT);
   1530             mCaller.sendMessage(message);
   1531         }
   1532 
   1533         public void onAccessibilityEvent(AccessibilityEvent event) {
   1534             Message message = mCaller.obtainMessageO(DO_ON_ACCESSIBILITY_EVENT, event);
   1535             mCaller.sendMessage(message);
   1536         }
   1537 
   1538         public void onGesture(int gestureId) {
   1539             Message message = mCaller.obtainMessageI(DO_ON_GESTURE, gestureId);
   1540             mCaller.sendMessage(message);
   1541         }
   1542 
   1543         public void clearAccessibilityCache() {
   1544             Message message = mCaller.obtainMessage(DO_CLEAR_ACCESSIBILITY_CACHE);
   1545             mCaller.sendMessage(message);
   1546         }
   1547 
   1548         @Override
   1549         public void onKeyEvent(KeyEvent event, int sequence) {
   1550             Message message = mCaller.obtainMessageIO(DO_ON_KEY_EVENT, sequence, event);
   1551             mCaller.sendMessage(message);
   1552         }
   1553 
   1554         public void onMagnificationChanged(@NonNull Region region,
   1555                 float scale, float centerX, float centerY) {
   1556             final SomeArgs args = SomeArgs.obtain();
   1557             args.arg1 = region;
   1558             args.arg2 = scale;
   1559             args.arg3 = centerX;
   1560             args.arg4 = centerY;
   1561 
   1562             final Message message = mCaller.obtainMessageO(DO_ON_MAGNIFICATION_CHANGED, args);
   1563             mCaller.sendMessage(message);
   1564         }
   1565 
   1566         public void onSoftKeyboardShowModeChanged(int showMode) {
   1567           final Message message =
   1568                   mCaller.obtainMessageI(DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED, showMode);
   1569           mCaller.sendMessage(message);
   1570         }
   1571 
   1572         public void onPerformGestureResult(int sequence, boolean successfully) {
   1573             Message message = mCaller.obtainMessageII(DO_GESTURE_COMPLETE, sequence,
   1574                     successfully ? 1 : 0);
   1575             mCaller.sendMessage(message);
   1576         }
   1577 
   1578         @Override
   1579         public void executeMessage(Message message) {
   1580             switch (message.what) {
   1581                 case DO_ON_ACCESSIBILITY_EVENT: {
   1582                     AccessibilityEvent event = (AccessibilityEvent) message.obj;
   1583                     if (event != null) {
   1584                         AccessibilityInteractionClient.getInstance().onAccessibilityEvent(event);
   1585                         mCallback.onAccessibilityEvent(event);
   1586                         // Make sure the event is recycled.
   1587                         try {
   1588                             event.recycle();
   1589                         } catch (IllegalStateException ise) {
   1590                             /* ignore - best effort */
   1591                         }
   1592                     }
   1593                 } return;
   1594 
   1595                 case DO_ON_INTERRUPT: {
   1596                     mCallback.onInterrupt();
   1597                 } return;
   1598 
   1599                 case DO_INIT: {
   1600                     mConnectionId = message.arg1;
   1601                     SomeArgs args = (SomeArgs) message.obj;
   1602                     IAccessibilityServiceConnection connection =
   1603                             (IAccessibilityServiceConnection) args.arg1;
   1604                     IBinder windowToken = (IBinder) args.arg2;
   1605                     args.recycle();
   1606                     if (connection != null) {
   1607                         AccessibilityInteractionClient.getInstance().addConnection(mConnectionId,
   1608                                 connection);
   1609                         mCallback.init(mConnectionId, windowToken);
   1610                         mCallback.onServiceConnected();
   1611                     } else {
   1612                         AccessibilityInteractionClient.getInstance().removeConnection(
   1613                                 mConnectionId);
   1614                         mConnectionId = AccessibilityInteractionClient.NO_ID;
   1615                         AccessibilityInteractionClient.getInstance().clearCache();
   1616                         mCallback.init(AccessibilityInteractionClient.NO_ID, null);
   1617                     }
   1618                 } return;
   1619 
   1620                 case DO_ON_GESTURE: {
   1621                     final int gestureId = message.arg1;
   1622                     mCallback.onGesture(gestureId);
   1623                 } return;
   1624 
   1625                 case DO_CLEAR_ACCESSIBILITY_CACHE: {
   1626                     AccessibilityInteractionClient.getInstance().clearCache();
   1627                 } return;
   1628 
   1629                 case DO_ON_KEY_EVENT: {
   1630                     KeyEvent event = (KeyEvent) message.obj;
   1631                     try {
   1632                         IAccessibilityServiceConnection connection = AccessibilityInteractionClient
   1633                                 .getInstance().getConnection(mConnectionId);
   1634                         if (connection != null) {
   1635                             final boolean result = mCallback.onKeyEvent(event);
   1636                             final int sequence = message.arg1;
   1637                             try {
   1638                                 connection.setOnKeyEventResult(result, sequence);
   1639                             } catch (RemoteException re) {
   1640                                 /* ignore */
   1641                             }
   1642                         }
   1643                     } finally {
   1644                         // Make sure the event is recycled.
   1645                         try {
   1646                             event.recycle();
   1647                         } catch (IllegalStateException ise) {
   1648                             /* ignore - best effort */
   1649                         }
   1650                     }
   1651                 } return;
   1652 
   1653                 case DO_ON_MAGNIFICATION_CHANGED: {
   1654                     final SomeArgs args = (SomeArgs) message.obj;
   1655                     final Region region = (Region) args.arg1;
   1656                     final float scale = (float) args.arg2;
   1657                     final float centerX = (float) args.arg3;
   1658                     final float centerY = (float) args.arg4;
   1659                     mCallback.onMagnificationChanged(region, scale, centerX, centerY);
   1660                 } return;
   1661 
   1662                 case DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED: {
   1663                     final int showMode = (int) message.arg1;
   1664                     mCallback.onSoftKeyboardShowModeChanged(showMode);
   1665                 } return;
   1666 
   1667                 case DO_GESTURE_COMPLETE: {
   1668                     final boolean successfully = message.arg2 == 1;
   1669                     mCallback.onPerformGestureResult(message.arg1, successfully);
   1670                 } return;
   1671 
   1672                 default :
   1673                     Log.w(LOG_TAG, "Unknown message type " + message.what);
   1674             }
   1675         }
   1676     }
   1677 
   1678     /**
   1679      * Class used to report status of dispatched gestures
   1680      */
   1681     public static abstract class GestureResultCallback {
   1682         /** Called when the gesture has completed successfully
   1683          *
   1684          * @param gestureDescription The description of the gesture that completed.
   1685          */
   1686         public void onCompleted(GestureDescription gestureDescription) {
   1687         }
   1688 
   1689         /** Called when the gesture was cancelled
   1690          *
   1691          * @param gestureDescription The description of the gesture that was cancelled.
   1692          */
   1693         public void onCancelled(GestureDescription gestureDescription) {
   1694         }
   1695     }
   1696 
   1697     /* Object to keep track of gesture result callbacks */
   1698     private static class GestureResultCallbackInfo {
   1699         GestureDescription gestureDescription;
   1700         GestureResultCallback callback;
   1701         Handler handler;
   1702 
   1703         GestureResultCallbackInfo(GestureDescription gestureDescription,
   1704                 GestureResultCallback callback, Handler handler) {
   1705             this.gestureDescription = gestureDescription;
   1706             this.callback = callback;
   1707             this.handler = handler;
   1708         }
   1709     }
   1710 }
   1711