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