Home | History | Annotate | Download | only in accessibility
      1 /*
      2  ** Copyright 2017, 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 com.android.server.accessibility;
     18 
     19 import static android.accessibilityservice.AccessibilityServiceInfo.DEFAULT;
     20 import static android.view.Display.DEFAULT_DISPLAY;
     21 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
     22 
     23 import android.accessibilityservice.AccessibilityServiceInfo;
     24 import android.accessibilityservice.IAccessibilityServiceClient;
     25 import android.accessibilityservice.IAccessibilityServiceConnection;
     26 import android.annotation.NonNull;
     27 import android.annotation.Nullable;
     28 import android.app.PendingIntent;
     29 import android.content.ComponentName;
     30 import android.content.Context;
     31 import android.content.Intent;
     32 import android.content.ServiceConnection;
     33 import android.content.pm.PackageManager;
     34 import android.content.pm.ParceledListSlice;
     35 import android.graphics.Region;
     36 import android.os.Binder;
     37 import android.os.Build;
     38 import android.os.Bundle;
     39 import android.os.Handler;
     40 import android.os.IBinder;
     41 import android.os.Looper;
     42 import android.os.Message;
     43 import android.os.RemoteException;
     44 import android.util.Slog;
     45 import android.util.SparseArray;
     46 import android.view.KeyEvent;
     47 import android.view.MagnificationSpec;
     48 import android.view.View;
     49 import android.view.accessibility.AccessibilityCache;
     50 import android.view.accessibility.AccessibilityEvent;
     51 import android.view.accessibility.AccessibilityNodeInfo;
     52 import android.view.accessibility.AccessibilityWindowInfo;
     53 import android.view.accessibility.IAccessibilityInteractionConnection;
     54 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
     55 
     56 import com.android.internal.os.SomeArgs;
     57 import com.android.internal.util.DumpUtils;
     58 import com.android.server.accessibility.AccessibilityManagerService.RemoteAccessibilityConnection;
     59 import com.android.server.accessibility.AccessibilityManagerService.SecurityPolicy;
     60 import com.android.server.wm.WindowManagerInternal;
     61 
     62 import java.io.FileDescriptor;
     63 import java.io.PrintWriter;
     64 import java.util.ArrayList;
     65 import java.util.Arrays;
     66 import java.util.HashSet;
     67 import java.util.List;
     68 import java.util.Set;
     69 
     70 /**
     71  * This class represents an accessibility client - either an AccessibilityService or a UiAutomation.
     72  * It is responsible for behavior common to both types of clients.
     73  */
     74 abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServiceConnection.Stub
     75         implements ServiceConnection, IBinder.DeathRecipient, KeyEventDispatcher.KeyEventFilter,
     76         FingerprintGestureDispatcher.FingerprintGestureClient {
     77     private static final boolean DEBUG = false;
     78     private static final String LOG_TAG = "AbstractAccessibilityServiceConnection";
     79 
     80     protected final Context mContext;
     81     protected final SystemSupport mSystemSupport;
     82     private final WindowManagerInternal mWindowManagerService;
     83     private final GlobalActionPerformer mGlobalActionPerformer;
     84 
     85     // Handler for scheduling method invocations on the main thread.
     86     public final InvocationHandler mInvocationHandler;
     87 
     88     final int mId;
     89 
     90     protected final AccessibilityServiceInfo mAccessibilityServiceInfo;
     91 
     92     // Lock must match the one used by AccessibilityManagerService
     93     protected final Object mLock;
     94 
     95     protected final SecurityPolicy mSecurityPolicy;
     96 
     97     // The service that's bound to this instance. Whenever this value is non-null, this
     98     // object is registered as a death recipient
     99     IBinder mService;
    100 
    101     IAccessibilityServiceClient mServiceInterface;
    102 
    103     int mEventTypes;
    104 
    105     int mFeedbackType;
    106 
    107     Set<String> mPackageNames = new HashSet<>();
    108 
    109     boolean mIsDefault;
    110 
    111     boolean mRequestTouchExplorationMode;
    112 
    113     boolean mRequestFilterKeyEvents;
    114 
    115     boolean mRetrieveInteractiveWindows;
    116 
    117     boolean mCaptureFingerprintGestures;
    118 
    119     boolean mRequestAccessibilityButton;
    120 
    121     boolean mReceivedAccessibilityButtonCallbackSinceBind;
    122 
    123     boolean mLastAccessibilityButtonCallbackState;
    124 
    125     int mFetchFlags;
    126 
    127     long mNotificationTimeout;
    128 
    129     final ComponentName mComponentName;
    130 
    131     // the events pending events to be dispatched to this service
    132     final SparseArray<AccessibilityEvent> mPendingEvents = new SparseArray<>();
    133 
    134     /** Whether this service relies on its {@link AccessibilityCache} being up to date */
    135     boolean mUsesAccessibilityCache = false;
    136 
    137     // Handler only for dispatching accessibility events since we use event
    138     // types as message types allowing us to remove messages per event type.
    139     public Handler mEventDispatchHandler;
    140 
    141     final IBinder mOverlayWindowToken = new Binder();
    142 
    143 
    144     public interface SystemSupport {
    145         /**
    146          * @return The current dispatcher for key events
    147          */
    148         @NonNull KeyEventDispatcher getKeyEventDispatcher();
    149 
    150         /**
    151          * @param windowId The id of the window of interest
    152          * @return The magnification spec for the window, or {@code null} if none is available
    153          */
    154         @Nullable MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId);
    155 
    156         /**
    157          * @return The current injector of motion events, if one exists
    158          */
    159         @Nullable MotionEventInjector getMotionEventInjectorLocked();
    160 
    161         /**
    162          * @return The current dispatcher for fingerprint gestures, if one exists
    163          */
    164         @Nullable FingerprintGestureDispatcher getFingerprintGestureDispatcher();
    165 
    166         /**
    167          * @return The magnification controller
    168          */
    169         @NonNull MagnificationController getMagnificationController();
    170 
    171         /**
    172          * Resolve a connection wrapper for a window id
    173          *
    174          * @param windowId The id of the window of interest
    175          *
    176          * @return a connection to the window
    177          */
    178         RemoteAccessibilityConnection getConnectionLocked(int windowId);
    179 
    180         /**
    181          * Perform the specified accessibility action
    182          *
    183          * @param resolvedWindowId The window ID
    184          * [Other parameters match the method on IAccessibilityServiceConnection]
    185          *
    186          * @return Whether or not the action could be sent to the app process
    187          */
    188         boolean performAccessibilityAction(int resolvedWindowId,
    189                 long accessibilityNodeId, int action, Bundle arguments, int interactionId,
    190                 IAccessibilityInteractionConnectionCallback callback, int fetchFlags,
    191                 long interrogatingTid);
    192 
    193         /**
    194          * Replace the interaction callback if needed, for example if the window is in picture-
    195          * in-picture mode and needs its nodes replaced.
    196          *
    197          * @param originalCallback The callback we were planning to use
    198          * @param resolvedWindowId The ID of the window we're calling
    199          * @param interactionId The id for the original callback
    200          * @param interrogatingPid Process ID of requester
    201          * @param interrogatingTid Thread ID of requester
    202          *
    203          * @return The callback to use, which may be the original one.
    204          */
    205         @NonNull IAccessibilityInteractionConnectionCallback replaceCallbackIfNeeded(
    206                 IAccessibilityInteractionConnectionCallback originalCallback,
    207                 int resolvedWindowId, int interactionId, int interrogatingPid,
    208                 long interrogatingTid);
    209 
    210         /**
    211          * Request that the system make sure windows are available to interrogate
    212          */
    213         void ensureWindowsAvailableTimed();
    214 
    215         /**
    216          * Called back to notify system that the client has changed
    217          * @param serviceInfoChanged True if the service's AccessibilityServiceInfo changed.
    218          */
    219         void onClientChange(boolean serviceInfoChanged);
    220 
    221         int getCurrentUserIdLocked();
    222 
    223         boolean isAccessibilityButtonShown();
    224 
    225         /**
    226          * Persists the component names in the specified setting in a
    227          * colon separated fashion.
    228          *
    229          * @param settingName The setting name.
    230          * @param componentNames The component names.
    231          * @param userId The user id to persist the setting for.
    232          */
    233         void persistComponentNamesToSettingLocked(String settingName,
    234                 Set<ComponentName> componentNames, int userId);
    235 
    236         /* This is exactly PendingIntent.getActivity, separated out for testability */
    237         PendingIntent getPendingIntentActivity(Context context, int requestCode, Intent intent,
    238                 int flags);
    239     }
    240 
    241     public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName,
    242             AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler,
    243             Object lock, SecurityPolicy securityPolicy, SystemSupport systemSupport,
    244             WindowManagerInternal windowManagerInternal,
    245             GlobalActionPerformer globalActionPerfomer) {
    246         mContext = context;
    247         mWindowManagerService = windowManagerInternal;
    248         mId = id;
    249         mComponentName = componentName;
    250         mAccessibilityServiceInfo = accessibilityServiceInfo;
    251         mLock = lock;
    252         mSecurityPolicy = securityPolicy;
    253         mGlobalActionPerformer = globalActionPerfomer;
    254         mSystemSupport = systemSupport;
    255         mInvocationHandler = new InvocationHandler(mainHandler.getLooper());
    256         mEventDispatchHandler = new Handler(mainHandler.getLooper()) {
    257             @Override
    258             public void handleMessage(Message message) {
    259                 final int eventType =  message.what;
    260                 AccessibilityEvent event = (AccessibilityEvent) message.obj;
    261                 boolean serviceWantsEvent = message.arg1 != 0;
    262                 notifyAccessibilityEventInternal(eventType, event, serviceWantsEvent);
    263             }
    264         };
    265         setDynamicallyConfigurableProperties(accessibilityServiceInfo);
    266     }
    267 
    268     @Override
    269     public boolean onKeyEvent(KeyEvent keyEvent, int sequenceNumber) {
    270         if (!mRequestFilterKeyEvents || (mServiceInterface == null)) {
    271             return false;
    272         }
    273         if((mAccessibilityServiceInfo.getCapabilities()
    274                 & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) == 0) {
    275             return false;
    276         }
    277         try {
    278             mServiceInterface.onKeyEvent(keyEvent, sequenceNumber);
    279         } catch (RemoteException e) {
    280             return false;
    281         }
    282         return true;
    283     }
    284 
    285     public void setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) {
    286         mEventTypes = info.eventTypes;
    287         mFeedbackType = info.feedbackType;
    288         String[] packageNames = info.packageNames;
    289         if (packageNames != null) {
    290             mPackageNames.addAll(Arrays.asList(packageNames));
    291         }
    292         mNotificationTimeout = info.notificationTimeout;
    293         mIsDefault = (info.flags & DEFAULT) != 0;
    294 
    295         if (supportsFlagForNotImportantViews(info)) {
    296             if ((info.flags & AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0) {
    297                 mFetchFlags |= AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
    298             } else {
    299                 mFetchFlags &= ~AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
    300             }
    301         }
    302 
    303         if ((info.flags & AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS) != 0) {
    304             mFetchFlags |= AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS;
    305         } else {
    306             mFetchFlags &= ~AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS;
    307         }
    308 
    309         mRequestTouchExplorationMode = (info.flags
    310                 & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
    311         mRequestFilterKeyEvents = (info.flags
    312                 & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0;
    313         mRetrieveInteractiveWindows = (info.flags
    314                 & AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS) != 0;
    315         mCaptureFingerprintGestures = (info.flags
    316                 & AccessibilityServiceInfo.FLAG_REQUEST_FINGERPRINT_GESTURES) != 0;
    317         mRequestAccessibilityButton = (info.flags
    318                 & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
    319     }
    320 
    321     protected boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) {
    322         return info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion
    323                 >= Build.VERSION_CODES.JELLY_BEAN;
    324     }
    325 
    326     public boolean canReceiveEventsLocked() {
    327         return (mEventTypes != 0 && mFeedbackType != 0 && mService != null);
    328     }
    329 
    330     @Override
    331     public void setOnKeyEventResult(boolean handled, int sequence) {
    332         mSystemSupport.getKeyEventDispatcher().setOnKeyEventResult(this, handled, sequence);
    333     }
    334 
    335     @Override
    336     public AccessibilityServiceInfo getServiceInfo() {
    337         synchronized (mLock) {
    338             return mAccessibilityServiceInfo;
    339         }
    340     }
    341 
    342     public int getCapabilities() {
    343         return mAccessibilityServiceInfo.getCapabilities();
    344     }
    345 
    346     int getRelevantEventTypes() {
    347         return (mUsesAccessibilityCache ? AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK : 0)
    348                 | mEventTypes;
    349     }
    350 
    351     @Override
    352     public void setServiceInfo(AccessibilityServiceInfo info) {
    353         final long identity = Binder.clearCallingIdentity();
    354         try {
    355             synchronized (mLock) {
    356                 // If the XML manifest had data to configure the service its info
    357                 // should be already set. In such a case update only the dynamically
    358                 // configurable properties.
    359                 AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo;
    360                 if (oldInfo != null) {
    361                     oldInfo.updateDynamicallyConfigurableProperties(info);
    362                     setDynamicallyConfigurableProperties(oldInfo);
    363                 } else {
    364                     setDynamicallyConfigurableProperties(info);
    365                 }
    366                 mSystemSupport.onClientChange(true);
    367             }
    368         } finally {
    369             Binder.restoreCallingIdentity(identity);
    370         }
    371     }
    372 
    373     protected abstract boolean isCalledForCurrentUserLocked();
    374 
    375     @Override
    376     public List<AccessibilityWindowInfo> getWindows() {
    377         mSystemSupport.ensureWindowsAvailableTimed();
    378         synchronized (mLock) {
    379             if (!isCalledForCurrentUserLocked()) {
    380                 return null;
    381             }
    382             final boolean permissionGranted =
    383                     mSecurityPolicy.canRetrieveWindowsLocked(this);
    384             if (!permissionGranted) {
    385                 return null;
    386             }
    387             if (mSecurityPolicy.mWindows == null) {
    388                 return null;
    389             }
    390             List<AccessibilityWindowInfo> windows = new ArrayList<>();
    391             final int windowCount = mSecurityPolicy.mWindows.size();
    392             for (int i = 0; i < windowCount; i++) {
    393                 AccessibilityWindowInfo window = mSecurityPolicy.mWindows.get(i);
    394                 AccessibilityWindowInfo windowClone =
    395                         AccessibilityWindowInfo.obtain(window);
    396                 windowClone.setConnectionId(mId);
    397                 windows.add(windowClone);
    398             }
    399             return windows;
    400         }
    401     }
    402 
    403     @Override
    404     public AccessibilityWindowInfo getWindow(int windowId) {
    405         mSystemSupport.ensureWindowsAvailableTimed();
    406         synchronized (mLock) {
    407             if (!isCalledForCurrentUserLocked()) {
    408                 return null;
    409             }
    410             final boolean permissionGranted =
    411                     mSecurityPolicy.canRetrieveWindowsLocked(this);
    412             if (!permissionGranted) {
    413                 return null;
    414             }
    415             AccessibilityWindowInfo window = mSecurityPolicy.findA11yWindowInfoById(windowId);
    416             if (window != null) {
    417                 AccessibilityWindowInfo windowClone = AccessibilityWindowInfo.obtain(window);
    418                 windowClone.setConnectionId(mId);
    419                 return windowClone;
    420             }
    421             return null;
    422         }
    423     }
    424 
    425     @Override
    426     public String[] findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
    427             long accessibilityNodeId, String viewIdResName, int interactionId,
    428             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
    429             throws RemoteException {
    430         final int resolvedWindowId;
    431         RemoteAccessibilityConnection connection;
    432         Region partialInteractiveRegion = Region.obtain();
    433         MagnificationSpec spec;
    434         synchronized (mLock) {
    435             mUsesAccessibilityCache = true;
    436             if (!isCalledForCurrentUserLocked()) {
    437                 return null;
    438             }
    439             resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
    440             final boolean permissionGranted =
    441                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
    442             if (!permissionGranted) {
    443                 return null;
    444             } else {
    445                 connection = mSystemSupport.getConnectionLocked(resolvedWindowId);
    446                 if (connection == null) {
    447                     return null;
    448                 }
    449             }
    450             if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
    451                     resolvedWindowId, partialInteractiveRegion)) {
    452                 partialInteractiveRegion.recycle();
    453                 partialInteractiveRegion = null;
    454             }
    455             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
    456         }
    457         final int interrogatingPid = Binder.getCallingPid();
    458         callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
    459                 interrogatingPid, interrogatingTid);
    460         final int callingUid = Binder.getCallingUid();
    461         final long identityToken = Binder.clearCallingIdentity();
    462         try {
    463             connection.getRemote().findAccessibilityNodeInfosByViewId(accessibilityNodeId,
    464                     viewIdResName, partialInteractiveRegion, interactionId, callback, mFetchFlags,
    465                     interrogatingPid, interrogatingTid, spec);
    466             return mSecurityPolicy.computeValidReportedPackages(callingUid,
    467                     connection.getPackageName(), connection.getUid());
    468         } catch (RemoteException re) {
    469             if (DEBUG) {
    470                 Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId().");
    471             }
    472         } finally {
    473             Binder.restoreCallingIdentity(identityToken);
    474             // Recycle if passed to another process.
    475             if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
    476                 partialInteractiveRegion.recycle();
    477             }
    478         }
    479         return null;
    480     }
    481 
    482     @Override
    483     public String[] findAccessibilityNodeInfosByText(int accessibilityWindowId,
    484             long accessibilityNodeId, String text, int interactionId,
    485             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
    486             throws RemoteException {
    487         final int resolvedWindowId;
    488         RemoteAccessibilityConnection connection;
    489         Region partialInteractiveRegion = Region.obtain();
    490         MagnificationSpec spec;
    491         synchronized (mLock) {
    492             mUsesAccessibilityCache = true;
    493             if (!isCalledForCurrentUserLocked()) {
    494                 return null;
    495             }
    496             resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
    497             final boolean permissionGranted =
    498                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
    499             if (!permissionGranted) {
    500                 return null;
    501             } else {
    502                 connection = mSystemSupport.getConnectionLocked(resolvedWindowId);
    503                 if (connection == null) {
    504                     return null;
    505                 }
    506             }
    507             if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
    508                     resolvedWindowId, partialInteractiveRegion)) {
    509                 partialInteractiveRegion.recycle();
    510                 partialInteractiveRegion = null;
    511             }
    512             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
    513         }
    514         final int interrogatingPid = Binder.getCallingPid();
    515         callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
    516                 interrogatingPid, interrogatingTid);
    517         final int callingUid = Binder.getCallingUid();
    518         final long identityToken = Binder.clearCallingIdentity();
    519         try {
    520             connection.getRemote().findAccessibilityNodeInfosByText(accessibilityNodeId,
    521                     text, partialInteractiveRegion, interactionId, callback, mFetchFlags,
    522                     interrogatingPid, interrogatingTid, spec);
    523             return mSecurityPolicy.computeValidReportedPackages(callingUid,
    524                     connection.getPackageName(), connection.getUid());
    525         } catch (RemoteException re) {
    526             if (DEBUG) {
    527                 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()");
    528             }
    529         } finally {
    530             Binder.restoreCallingIdentity(identityToken);
    531             // Recycle if passed to another process.
    532             if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
    533                 partialInteractiveRegion.recycle();
    534             }
    535         }
    536         return null;
    537     }
    538 
    539     @Override
    540     public String[] findAccessibilityNodeInfoByAccessibilityId(
    541             int accessibilityWindowId, long accessibilityNodeId, int interactionId,
    542             IAccessibilityInteractionConnectionCallback callback, int flags,
    543             long interrogatingTid, Bundle arguments) throws RemoteException {
    544         final int resolvedWindowId;
    545         RemoteAccessibilityConnection connection;
    546         Region partialInteractiveRegion = Region.obtain();
    547         MagnificationSpec spec;
    548         synchronized (mLock) {
    549             mUsesAccessibilityCache = true;
    550             if (!isCalledForCurrentUserLocked()) {
    551                 return null;
    552             }
    553             resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
    554             final boolean permissionGranted =
    555                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
    556             if (!permissionGranted) {
    557                 return null;
    558             } else {
    559                 connection = mSystemSupport.getConnectionLocked(resolvedWindowId);
    560                 if (connection == null) {
    561                     return null;
    562                 }
    563             }
    564             if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
    565                     resolvedWindowId, partialInteractiveRegion)) {
    566                 partialInteractiveRegion.recycle();
    567                 partialInteractiveRegion = null;
    568             }
    569             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
    570         }
    571         final int interrogatingPid = Binder.getCallingPid();
    572         callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
    573                 interrogatingPid, interrogatingTid);
    574         final int callingUid = Binder.getCallingUid();
    575         final long identityToken = Binder.clearCallingIdentity();
    576         try {
    577             connection.getRemote().findAccessibilityNodeInfoByAccessibilityId(
    578                     accessibilityNodeId, partialInteractiveRegion, interactionId, callback,
    579                     mFetchFlags | flags, interrogatingPid, interrogatingTid, spec, arguments);
    580             return mSecurityPolicy.computeValidReportedPackages(callingUid,
    581                     connection.getPackageName(), connection.getUid());
    582         } catch (RemoteException re) {
    583             if (DEBUG) {
    584                 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
    585             }
    586         } finally {
    587             Binder.restoreCallingIdentity(identityToken);
    588             // Recycle if passed to another process.
    589             if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
    590                 partialInteractiveRegion.recycle();
    591             }
    592         }
    593         return null;
    594     }
    595 
    596     @Override
    597     public String[] findFocus(int accessibilityWindowId, long accessibilityNodeId,
    598             int focusType, int interactionId,
    599             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
    600             throws RemoteException {
    601         final int resolvedWindowId;
    602         RemoteAccessibilityConnection connection;
    603         Region partialInteractiveRegion = Region.obtain();
    604         MagnificationSpec spec;
    605         synchronized (mLock) {
    606             if (!isCalledForCurrentUserLocked()) {
    607                 return null;
    608             }
    609             resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked(
    610                     accessibilityWindowId, focusType);
    611             final boolean permissionGranted =
    612                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
    613             if (!permissionGranted) {
    614                 return null;
    615             } else {
    616                 connection = mSystemSupport.getConnectionLocked(resolvedWindowId);
    617                 if (connection == null) {
    618                     return null;
    619                 }
    620             }
    621             if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
    622                     resolvedWindowId, partialInteractiveRegion)) {
    623                 partialInteractiveRegion.recycle();
    624                 partialInteractiveRegion = null;
    625             }
    626             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
    627         }
    628         final int interrogatingPid = Binder.getCallingPid();
    629         callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
    630                 interrogatingPid, interrogatingTid);
    631         final int callingUid = Binder.getCallingUid();
    632         final long identityToken = Binder.clearCallingIdentity();
    633         try {
    634             connection.getRemote().findFocus(accessibilityNodeId, focusType,
    635                     partialInteractiveRegion, interactionId, callback, mFetchFlags,
    636                     interrogatingPid, interrogatingTid, spec);
    637             return mSecurityPolicy.computeValidReportedPackages(callingUid,
    638                     connection.getPackageName(), connection.getUid());
    639         } catch (RemoteException re) {
    640             if (DEBUG) {
    641                 Slog.e(LOG_TAG, "Error calling findFocus()");
    642             }
    643         } finally {
    644             Binder.restoreCallingIdentity(identityToken);
    645             // Recycle if passed to another process.
    646             if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
    647                 partialInteractiveRegion.recycle();
    648             }
    649         }
    650         return null;
    651     }
    652 
    653     @Override
    654     public String[] focusSearch(int accessibilityWindowId, long accessibilityNodeId,
    655             int direction, int interactionId,
    656             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
    657             throws RemoteException {
    658         final int resolvedWindowId;
    659         RemoteAccessibilityConnection connection;
    660         Region partialInteractiveRegion = Region.obtain();
    661         MagnificationSpec spec;
    662         synchronized (mLock) {
    663             if (!isCalledForCurrentUserLocked()) {
    664                 return null;
    665             }
    666             resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
    667             final boolean permissionGranted =
    668                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
    669             if (!permissionGranted) {
    670                 return null;
    671             } else {
    672                 connection = mSystemSupport.getConnectionLocked(resolvedWindowId);
    673                 if (connection == null) {
    674                     return null;
    675                 }
    676             }
    677             if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
    678                     resolvedWindowId, partialInteractiveRegion)) {
    679                 partialInteractiveRegion.recycle();
    680                 partialInteractiveRegion = null;
    681             }
    682             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
    683         }
    684         final int interrogatingPid = Binder.getCallingPid();
    685         callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
    686                 interrogatingPid, interrogatingTid);
    687         final int callingUid = Binder.getCallingUid();
    688         final long identityToken = Binder.clearCallingIdentity();
    689         try {
    690             connection.getRemote().focusSearch(accessibilityNodeId, direction,
    691                     partialInteractiveRegion, interactionId, callback, mFetchFlags,
    692                     interrogatingPid, interrogatingTid, spec);
    693             return mSecurityPolicy.computeValidReportedPackages(callingUid,
    694                     connection.getPackageName(), connection.getUid());
    695         } catch (RemoteException re) {
    696             if (DEBUG) {
    697                 Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()");
    698             }
    699         } finally {
    700             Binder.restoreCallingIdentity(identityToken);
    701             // Recycle if passed to another process.
    702             if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
    703                 partialInteractiveRegion.recycle();
    704             }
    705         }
    706         return null;
    707     }
    708 
    709     @Override
    710     public void sendGesture(int sequence, ParceledListSlice gestureSteps) {
    711     }
    712 
    713     @Override
    714     public boolean performAccessibilityAction(int accessibilityWindowId,
    715             long accessibilityNodeId, int action, Bundle arguments, int interactionId,
    716             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
    717             throws RemoteException {
    718         final int resolvedWindowId;
    719         IAccessibilityInteractionConnection connection = null;
    720         synchronized (mLock) {
    721             if (!isCalledForCurrentUserLocked()) {
    722                 return false;
    723             }
    724             resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
    725             if (!mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId)) {
    726                 return false;
    727             }
    728         }
    729         boolean returnValue =
    730                 mSystemSupport.performAccessibilityAction(resolvedWindowId, accessibilityNodeId,
    731                 action, arguments, interactionId, callback, mFetchFlags, interrogatingTid);
    732         return returnValue;
    733     }
    734 
    735     @Override
    736     public boolean performGlobalAction(int action) {
    737         synchronized (mLock) {
    738             if (!isCalledForCurrentUserLocked()) {
    739                 return false;
    740             }
    741         }
    742         return mGlobalActionPerformer.performGlobalAction(action);
    743     }
    744 
    745     @Override
    746     public boolean isFingerprintGestureDetectionAvailable() {
    747         if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
    748             return false;
    749         }
    750         if (isCapturingFingerprintGestures()) {
    751             FingerprintGestureDispatcher dispatcher =
    752                     mSystemSupport.getFingerprintGestureDispatcher();
    753             return (dispatcher != null) && dispatcher.isFingerprintGestureDetectionAvailable();
    754         }
    755         return false;
    756     }
    757 
    758     @Override
    759     public float getMagnificationScale() {
    760         synchronized (mLock) {
    761             if (!isCalledForCurrentUserLocked()) {
    762                 return 1.0f;
    763             }
    764         }
    765         final long identity = Binder.clearCallingIdentity();
    766         try {
    767             return mSystemSupport.getMagnificationController().getScale();
    768         } finally {
    769             Binder.restoreCallingIdentity(identity);
    770         }
    771     }
    772 
    773     @Override
    774     public Region getMagnificationRegion() {
    775         synchronized (mLock) {
    776             final Region region = Region.obtain();
    777             if (!isCalledForCurrentUserLocked()) {
    778                 return region;
    779             }
    780             MagnificationController magnificationController =
    781                     mSystemSupport.getMagnificationController();
    782             boolean registeredJustForThisCall =
    783                     registerMagnificationIfNeeded(magnificationController);
    784             final long identity = Binder.clearCallingIdentity();
    785             try {
    786                 magnificationController.getMagnificationRegion(region);
    787                 return region;
    788             } finally {
    789                 Binder.restoreCallingIdentity(identity);
    790                 if (registeredJustForThisCall) {
    791                     magnificationController.unregister();
    792                 }
    793             }
    794         }
    795     }
    796 
    797     @Override
    798     public float getMagnificationCenterX() {
    799         synchronized (mLock) {
    800             if (!isCalledForCurrentUserLocked()) {
    801                 return 0.0f;
    802             }
    803             MagnificationController magnificationController =
    804                     mSystemSupport.getMagnificationController();
    805             boolean registeredJustForThisCall =
    806                     registerMagnificationIfNeeded(magnificationController);
    807             final long identity = Binder.clearCallingIdentity();
    808             try {
    809                 return magnificationController.getCenterX();
    810             } finally {
    811                 Binder.restoreCallingIdentity(identity);
    812                 if (registeredJustForThisCall) {
    813                     magnificationController.unregister();
    814                 }
    815             }
    816         }
    817     }
    818 
    819     @Override
    820     public float getMagnificationCenterY() {
    821         synchronized (mLock) {
    822             if (!isCalledForCurrentUserLocked()) {
    823                 return 0.0f;
    824             }
    825             MagnificationController magnificationController =
    826                     mSystemSupport.getMagnificationController();
    827             boolean registeredJustForThisCall =
    828                     registerMagnificationIfNeeded(magnificationController);
    829             final long identity = Binder.clearCallingIdentity();
    830             try {
    831                 return magnificationController.getCenterY();
    832             } finally {
    833                 Binder.restoreCallingIdentity(identity);
    834                 if (registeredJustForThisCall) {
    835                     magnificationController.unregister();
    836                 }
    837             }
    838         }
    839     }
    840 
    841     private boolean registerMagnificationIfNeeded(
    842             MagnificationController magnificationController) {
    843         if (!magnificationController.isRegisteredLocked()
    844                 && mSecurityPolicy.canControlMagnification(this)) {
    845             magnificationController.register();
    846             return true;
    847         }
    848         return false;
    849     }
    850 
    851     @Override
    852     public boolean resetMagnification(boolean animate) {
    853         synchronized (mLock) {
    854             if (!isCalledForCurrentUserLocked()) {
    855                 return false;
    856             }
    857             if (!mSecurityPolicy.canControlMagnification(this)) {
    858                 return false;
    859             }
    860         }
    861         final long identity = Binder.clearCallingIdentity();
    862         try {
    863             return mSystemSupport.getMagnificationController().reset(animate);
    864         } finally {
    865             Binder.restoreCallingIdentity(identity);
    866         }
    867     }
    868 
    869     @Override
    870     public boolean setMagnificationScaleAndCenter(float scale, float centerX, float centerY,
    871             boolean animate) {
    872         synchronized (mLock) {
    873             if (!isCalledForCurrentUserLocked()) {
    874                 return false;
    875             }
    876             if (!mSecurityPolicy.canControlMagnification(this)) {
    877                 return false;
    878             }
    879             final long identity = Binder.clearCallingIdentity();
    880             try {
    881                 MagnificationController magnificationController =
    882                         mSystemSupport.getMagnificationController();
    883                 if (!magnificationController.isRegisteredLocked()) {
    884                     magnificationController.register();
    885                 }
    886                 return magnificationController
    887                         .setScaleAndCenter(scale, centerX, centerY, animate, mId);
    888             } finally {
    889                 Binder.restoreCallingIdentity(identity);
    890             }
    891         }
    892     }
    893 
    894     @Override
    895     public void setMagnificationCallbackEnabled(boolean enabled) {
    896         mInvocationHandler.setMagnificationCallbackEnabled(enabled);
    897     }
    898 
    899     public boolean isMagnificationCallbackEnabled() {
    900         return mInvocationHandler.mIsMagnificationCallbackEnabled;
    901     }
    902 
    903     @Override
    904     public void setSoftKeyboardCallbackEnabled(boolean enabled) {
    905         mInvocationHandler.setSoftKeyboardCallbackEnabled(enabled);
    906     }
    907 
    908     @Override
    909     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
    910         if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
    911         synchronized (mLock) {
    912             pw.append("Service[label=" + mAccessibilityServiceInfo.getResolveInfo()
    913                     .loadLabel(mContext.getPackageManager()));
    914             pw.append(", feedbackType"
    915                     + AccessibilityServiceInfo.feedbackTypeToString(mFeedbackType));
    916             pw.append(", capabilities=" + mAccessibilityServiceInfo.getCapabilities());
    917             pw.append(", eventTypes="
    918                     + AccessibilityEvent.eventTypeToString(mEventTypes));
    919             pw.append(", notificationTimeout=" + mNotificationTimeout);
    920             pw.append("]");
    921         }
    922     }
    923 
    924     public void onAdded() {
    925         final long identity = Binder.clearCallingIdentity();
    926         try {
    927             mWindowManagerService.addWindowToken(mOverlayWindowToken,
    928                     TYPE_ACCESSIBILITY_OVERLAY, DEFAULT_DISPLAY);
    929         } finally {
    930             Binder.restoreCallingIdentity(identity);
    931         }
    932     }
    933 
    934     public void onRemoved() {
    935         final long identity = Binder.clearCallingIdentity();
    936         try {
    937             mWindowManagerService.removeWindowToken(mOverlayWindowToken, true, DEFAULT_DISPLAY);
    938         } finally {
    939             Binder.restoreCallingIdentity(identity);
    940         }
    941     }
    942 
    943     public void resetLocked() {
    944         mSystemSupport.getKeyEventDispatcher().flush(this);
    945         try {
    946             // Clear the proxy in the other process so this
    947             // IAccessibilityServiceConnection can be garbage collected.
    948             if (mServiceInterface != null) {
    949                 mServiceInterface.init(null, mId, null);
    950             }
    951         } catch (RemoteException re) {
    952                 /* ignore */
    953         }
    954         if (mService != null) {
    955             mService.unlinkToDeath(this, 0);
    956             mService = null;
    957         }
    958 
    959         mServiceInterface = null;
    960         mReceivedAccessibilityButtonCallbackSinceBind = false;
    961     }
    962 
    963     public boolean isConnectedLocked() {
    964         return (mService != null);
    965     }
    966 
    967     public void notifyAccessibilityEvent(AccessibilityEvent event) {
    968         synchronized (mLock) {
    969             final int eventType = event.getEventType();
    970 
    971             final boolean serviceWantsEvent = wantsEventLocked(event);
    972             final boolean requiredForCacheConsistency = mUsesAccessibilityCache
    973                     && ((AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK & eventType) != 0);
    974             if (!serviceWantsEvent && !requiredForCacheConsistency) {
    975                 return;
    976             }
    977 
    978             // Make a copy since during dispatch it is possible the event to
    979             // be modified to remove its source if the receiving service does
    980             // not have permission to access the window content.
    981             AccessibilityEvent newEvent = AccessibilityEvent.obtain(event);
    982             Message message;
    983             if ((mNotificationTimeout > 0)
    984                     && (eventType != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED)) {
    985                 // Allow at most one pending event
    986                 final AccessibilityEvent oldEvent = mPendingEvents.get(eventType);
    987                 mPendingEvents.put(eventType, newEvent);
    988                 if (oldEvent != null) {
    989                     mEventDispatchHandler.removeMessages(eventType);
    990                     oldEvent.recycle();
    991                 }
    992                 message = mEventDispatchHandler.obtainMessage(eventType);
    993             } else {
    994                 // Send all messages, bypassing mPendingEvents
    995                 message = mEventDispatchHandler.obtainMessage(eventType, newEvent);
    996             }
    997             message.arg1 = serviceWantsEvent ? 1 : 0;
    998 
    999             mEventDispatchHandler.sendMessageDelayed(message, mNotificationTimeout);
   1000         }
   1001     }
   1002 
   1003     /**
   1004      * Determines if given event can be dispatched to a service based on the package of the
   1005      * event source. Specifically, a service is notified if it is interested in events from the
   1006      * package.
   1007      *
   1008      * @param event The event.
   1009      * @return True if the listener should be notified, false otherwise.
   1010      */
   1011     private boolean wantsEventLocked(AccessibilityEvent event) {
   1012 
   1013         if (!canReceiveEventsLocked()) {
   1014             return false;
   1015         }
   1016 
   1017         if ((event.getWindowId() != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID)
   1018                 && !event.isImportantForAccessibility()
   1019                 && (mFetchFlags & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) {
   1020             return false;
   1021         }
   1022 
   1023         int eventType = event.getEventType();
   1024         if ((mEventTypes & eventType) != eventType) {
   1025             return false;
   1026         }
   1027 
   1028         Set<String> packageNames = mPackageNames;
   1029         String packageName = (event.getPackageName() != null)
   1030                 ? event.getPackageName().toString() : null;
   1031 
   1032         return (packageNames.isEmpty() || packageNames.contains(packageName));
   1033     }
   1034 
   1035     /**
   1036      * Notifies an accessibility service client for a scheduled event given the event type.
   1037      *
   1038      * @param eventType The type of the event to dispatch.
   1039      */
   1040     private void notifyAccessibilityEventInternal(
   1041             int eventType,
   1042             AccessibilityEvent event,
   1043             boolean serviceWantsEvent) {
   1044         IAccessibilityServiceClient listener;
   1045 
   1046         synchronized (mLock) {
   1047             listener = mServiceInterface;
   1048 
   1049             // If the service died/was disabled while the message for dispatching
   1050             // the accessibility event was propagating the listener may be null.
   1051             if (listener == null) {
   1052                 return;
   1053             }
   1054 
   1055             // There are two ways we notify for events, throttled AND non-throttled. If we
   1056             // are not throttling, then messages come with events, which we handle with
   1057             // minimal fuss.
   1058             if (event == null) {
   1059                 // We are throttling events, so we'll send the event for this type in
   1060                 // mPendingEvents as long as it it's null. It can only null due to a race
   1061                 // condition:
   1062                 //
   1063                 //   1) A binder thread calls notifyAccessibilityServiceDelayedLocked
   1064                 //      which posts a message for dispatching an event and stores the event
   1065                 //      in mPendingEvents.
   1066                 //   2) The message is pulled from the queue by the handler on the service
   1067                 //      thread and this method is just about to acquire the lock.
   1068                 //   3) Another binder thread acquires the lock in notifyAccessibilityEvent
   1069                 //   4) notifyAccessibilityEvent recycles the event that this method was about
   1070                 //      to process, replaces it with a new one, and posts a second message
   1071                 //   5) This method grabs the new event, processes it, and removes it from
   1072                 //      mPendingEvents
   1073                 //   6) The second message dispatched in (4) arrives, but the event has been
   1074                 //      remvoved in (5).
   1075                 event = mPendingEvents.get(eventType);
   1076                 if (event == null) {
   1077                     return;
   1078                 }
   1079                 mPendingEvents.remove(eventType);
   1080             }
   1081             if (mSecurityPolicy.canRetrieveWindowContentLocked(this)) {
   1082                 event.setConnectionId(mId);
   1083             } else {
   1084                 event.setSource((View) null);
   1085             }
   1086             event.setSealed(true);
   1087         }
   1088 
   1089         try {
   1090             listener.onAccessibilityEvent(event, serviceWantsEvent);
   1091             if (DEBUG) {
   1092                 Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
   1093             }
   1094         } catch (RemoteException re) {
   1095             Slog.e(LOG_TAG, "Error during sending " + event + " to " + listener, re);
   1096         } finally {
   1097             event.recycle();
   1098         }
   1099     }
   1100 
   1101     public void notifyGesture(int gestureId) {
   1102         mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_GESTURE,
   1103                 gestureId, 0).sendToTarget();
   1104     }
   1105 
   1106     public void notifyClearAccessibilityNodeInfoCache() {
   1107         mInvocationHandler.sendEmptyMessage(
   1108                 InvocationHandler.MSG_CLEAR_ACCESSIBILITY_CACHE);
   1109     }
   1110 
   1111     public void notifyMagnificationChangedLocked(@NonNull Region region,
   1112             float scale, float centerX, float centerY) {
   1113         mInvocationHandler
   1114                 .notifyMagnificationChangedLocked(region, scale, centerX, centerY);
   1115     }
   1116 
   1117     public void notifySoftKeyboardShowModeChangedLocked(int showState) {
   1118         mInvocationHandler.notifySoftKeyboardShowModeChangedLocked(showState);
   1119     }
   1120 
   1121     public void notifyAccessibilityButtonClickedLocked() {
   1122         mInvocationHandler.notifyAccessibilityButtonClickedLocked();
   1123     }
   1124 
   1125     public void notifyAccessibilityButtonAvailabilityChangedLocked(boolean available) {
   1126         mInvocationHandler.notifyAccessibilityButtonAvailabilityChangedLocked(available);
   1127     }
   1128 
   1129     /**
   1130      * Called by the invocation handler to notify the service that the
   1131      * state of magnification has changed.
   1132      */
   1133     private void notifyMagnificationChangedInternal(@NonNull Region region,
   1134             float scale, float centerX, float centerY) {
   1135         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
   1136         if (listener != null) {
   1137             try {
   1138                 listener.onMagnificationChanged(region, scale, centerX, centerY);
   1139             } catch (RemoteException re) {
   1140                 Slog.e(LOG_TAG, "Error sending magnification changes to " + mService, re);
   1141             }
   1142         }
   1143     }
   1144 
   1145     /**
   1146      * Called by the invocation handler to notify the service that the state of the soft
   1147      * keyboard show mode has changed.
   1148      */
   1149     private void notifySoftKeyboardShowModeChangedInternal(int showState) {
   1150         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
   1151         if (listener != null) {
   1152             try {
   1153                 listener.onSoftKeyboardShowModeChanged(showState);
   1154             } catch (RemoteException re) {
   1155                 Slog.e(LOG_TAG, "Error sending soft keyboard show mode changes to " + mService,
   1156                         re);
   1157             }
   1158         }
   1159     }
   1160 
   1161     private void notifyAccessibilityButtonClickedInternal() {
   1162         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
   1163         if (listener != null) {
   1164             try {
   1165                 listener.onAccessibilityButtonClicked();
   1166             } catch (RemoteException re) {
   1167                 Slog.e(LOG_TAG, "Error sending accessibility button click to " + mService, re);
   1168             }
   1169         }
   1170     }
   1171 
   1172     private void notifyAccessibilityButtonAvailabilityChangedInternal(boolean available) {
   1173         // Only notify the service if it's not been notified or the state has changed
   1174         if (mReceivedAccessibilityButtonCallbackSinceBind
   1175                 && (mLastAccessibilityButtonCallbackState == available)) {
   1176             return;
   1177         }
   1178         mReceivedAccessibilityButtonCallbackSinceBind = true;
   1179         mLastAccessibilityButtonCallbackState = available;
   1180         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
   1181         if (listener != null) {
   1182             try {
   1183                 listener.onAccessibilityButtonAvailabilityChanged(available);
   1184             } catch (RemoteException re) {
   1185                 Slog.e(LOG_TAG,
   1186                         "Error sending accessibility button availability change to " + mService,
   1187                         re);
   1188             }
   1189         }
   1190     }
   1191 
   1192     private void notifyGestureInternal(int gestureId) {
   1193         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
   1194         if (listener != null) {
   1195             try {
   1196                 listener.onGesture(gestureId);
   1197             } catch (RemoteException re) {
   1198                 Slog.e(LOG_TAG, "Error during sending gesture " + gestureId
   1199                         + " to " + mService, re);
   1200             }
   1201         }
   1202     }
   1203 
   1204     private void notifyClearAccessibilityCacheInternal() {
   1205         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
   1206         if (listener != null) {
   1207             try {
   1208                 listener.clearAccessibilityCache();
   1209             } catch (RemoteException re) {
   1210                 Slog.e(LOG_TAG, "Error during requesting accessibility info cache"
   1211                         + " to be cleared.", re);
   1212             }
   1213         }
   1214     }
   1215 
   1216     private IAccessibilityServiceClient getServiceInterfaceSafely() {
   1217         synchronized (mLock) {
   1218             return mServiceInterface;
   1219         }
   1220     }
   1221 
   1222     private int resolveAccessibilityWindowIdLocked(int accessibilityWindowId) {
   1223         if (accessibilityWindowId == AccessibilityWindowInfo.ACTIVE_WINDOW_ID) {
   1224             return mSecurityPolicy.getActiveWindowId();
   1225         }
   1226         return accessibilityWindowId;
   1227     }
   1228 
   1229     private int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) {
   1230         if (windowId == AccessibilityWindowInfo.ACTIVE_WINDOW_ID) {
   1231             return mSecurityPolicy.mActiveWindowId;
   1232         }
   1233         if (windowId == AccessibilityWindowInfo.ANY_WINDOW_ID) {
   1234             if (focusType == AccessibilityNodeInfo.FOCUS_INPUT) {
   1235                 return mSecurityPolicy.mFocusedWindowId;
   1236             } else if (focusType == AccessibilityNodeInfo.FOCUS_ACCESSIBILITY) {
   1237                 return mSecurityPolicy.mAccessibilityFocusedWindowId;
   1238             }
   1239         }
   1240         return windowId;
   1241     }
   1242 
   1243     public ComponentName getComponentName() {
   1244         return mComponentName;
   1245     }
   1246 
   1247     private final class InvocationHandler extends Handler {
   1248         public static final int MSG_ON_GESTURE = 1;
   1249         public static final int MSG_CLEAR_ACCESSIBILITY_CACHE = 2;
   1250 
   1251         private static final int MSG_ON_MAGNIFICATION_CHANGED = 5;
   1252         private static final int MSG_ON_SOFT_KEYBOARD_STATE_CHANGED = 6;
   1253         private static final int MSG_ON_ACCESSIBILITY_BUTTON_CLICKED = 7;
   1254         private static final int MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 8;
   1255 
   1256         private boolean mIsMagnificationCallbackEnabled = false;
   1257         private boolean mIsSoftKeyboardCallbackEnabled = false;
   1258 
   1259         public InvocationHandler(Looper looper) {
   1260             super(looper, null, true);
   1261         }
   1262 
   1263         @Override
   1264         public void handleMessage(Message message) {
   1265             final int type = message.what;
   1266             switch (type) {
   1267                 case MSG_ON_GESTURE: {
   1268                     final int gestureId = message.arg1;
   1269                     notifyGestureInternal(gestureId);
   1270                 } break;
   1271 
   1272                 case MSG_CLEAR_ACCESSIBILITY_CACHE: {
   1273                     notifyClearAccessibilityCacheInternal();
   1274                 } break;
   1275 
   1276                 case MSG_ON_MAGNIFICATION_CHANGED: {
   1277                     final SomeArgs args = (SomeArgs) message.obj;
   1278                     final Region region = (Region) args.arg1;
   1279                     final float scale = (float) args.arg2;
   1280                     final float centerX = (float) args.arg3;
   1281                     final float centerY = (float) args.arg4;
   1282                     notifyMagnificationChangedInternal(region, scale, centerX, centerY);
   1283                     args.recycle();
   1284                 } break;
   1285 
   1286                 case MSG_ON_SOFT_KEYBOARD_STATE_CHANGED: {
   1287                     final int showState = (int) message.arg1;
   1288                     notifySoftKeyboardShowModeChangedInternal(showState);
   1289                 } break;
   1290 
   1291                 case MSG_ON_ACCESSIBILITY_BUTTON_CLICKED: {
   1292                     notifyAccessibilityButtonClickedInternal();
   1293                 } break;
   1294 
   1295                 case MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED: {
   1296                     final boolean available = (message.arg1 != 0);
   1297                     notifyAccessibilityButtonAvailabilityChangedInternal(available);
   1298                 } break;
   1299 
   1300                 default: {
   1301                     throw new IllegalArgumentException("Unknown message: " + type);
   1302                 }
   1303             }
   1304         }
   1305 
   1306         public void notifyMagnificationChangedLocked(@NonNull Region region, float scale,
   1307                 float centerX, float centerY) {
   1308             if (!mIsMagnificationCallbackEnabled) {
   1309                 // Callback is disabled, don't bother packing args.
   1310                 return;
   1311             }
   1312 
   1313             final SomeArgs args = SomeArgs.obtain();
   1314             args.arg1 = region;
   1315             args.arg2 = scale;
   1316             args.arg3 = centerX;
   1317             args.arg4 = centerY;
   1318 
   1319             final Message msg = obtainMessage(MSG_ON_MAGNIFICATION_CHANGED, args);
   1320             msg.sendToTarget();
   1321         }
   1322 
   1323         public void setMagnificationCallbackEnabled(boolean enabled) {
   1324             mIsMagnificationCallbackEnabled = enabled;
   1325         }
   1326 
   1327         public void notifySoftKeyboardShowModeChangedLocked(int showState) {
   1328             if (!mIsSoftKeyboardCallbackEnabled) {
   1329                 return;
   1330             }
   1331 
   1332             final Message msg = obtainMessage(MSG_ON_SOFT_KEYBOARD_STATE_CHANGED, showState, 0);
   1333             msg.sendToTarget();
   1334         }
   1335 
   1336         public void setSoftKeyboardCallbackEnabled(boolean enabled) {
   1337             mIsSoftKeyboardCallbackEnabled = enabled;
   1338         }
   1339 
   1340         public void notifyAccessibilityButtonClickedLocked() {
   1341             final Message msg = obtainMessage(MSG_ON_ACCESSIBILITY_BUTTON_CLICKED);
   1342             msg.sendToTarget();
   1343         }
   1344 
   1345         public void notifyAccessibilityButtonAvailabilityChangedLocked(boolean available) {
   1346             final Message msg = obtainMessage(MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED,
   1347                     (available ? 1 : 0), 0);
   1348             msg.sendToTarget();
   1349         }
   1350     }
   1351 }
   1352