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.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE;
20 import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER;
21 import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_STATUS;
22 import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP;
23 import static android.accessibilityservice.AccessibilityServiceInfo.DEFAULT;
24 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
25 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS;
26 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
27 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
28 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
29 
30 import android.accessibilityservice.AccessibilityGestureEvent;
31 import android.accessibilityservice.AccessibilityService;
32 import android.accessibilityservice.AccessibilityServiceInfo;
33 import android.accessibilityservice.IAccessibilityServiceClient;
34 import android.accessibilityservice.IAccessibilityServiceConnection;
35 import android.annotation.NonNull;
36 import android.annotation.Nullable;
37 import android.app.PendingIntent;
38 import android.content.ComponentName;
39 import android.content.Context;
40 import android.content.Intent;
41 import android.content.ServiceConnection;
42 import android.content.pm.PackageManager;
43 import android.content.pm.ParceledListSlice;
44 import android.graphics.GraphicBuffer;
45 import android.graphics.ParcelableColorSpace;
46 import android.graphics.Region;
47 import android.hardware.HardwareBuffer;
48 import android.hardware.display.DisplayManager;
49 import android.hardware.display.DisplayManagerInternal;
50 import android.os.Binder;
51 import android.os.Build;
52 import android.os.Bundle;
53 import android.os.Handler;
54 import android.os.IBinder;
55 import android.os.Looper;
56 import android.os.Message;
57 import android.os.PowerManager;
58 import android.os.RemoteCallback;
59 import android.os.RemoteException;
60 import android.os.ServiceManager;
61 import android.os.SystemClock;
62 import android.util.Slog;
63 import android.util.SparseArray;
64 import android.view.Display;
65 import android.view.KeyEvent;
66 import android.view.MagnificationSpec;
67 import android.view.SurfaceControl.ScreenshotGraphicBuffer;
68 import android.view.View;
69 import android.view.WindowInfo;
70 import android.view.accessibility.AccessibilityCache;
71 import android.view.accessibility.AccessibilityEvent;
72 import android.view.accessibility.AccessibilityNodeInfo;
73 import android.view.accessibility.AccessibilityWindowInfo;
74 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
75 
76 import com.android.internal.annotations.GuardedBy;
77 import com.android.internal.compat.IPlatformCompat;
78 import com.android.internal.os.SomeArgs;
79 import com.android.internal.util.DumpUtils;
80 import com.android.internal.util.function.pooled.PooledLambda;
81 import com.android.server.LocalServices;
82 import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
83 import com.android.server.wm.ActivityTaskManagerInternal;
84 import com.android.server.wm.WindowManagerInternal;
85 
86 import java.io.FileDescriptor;
87 import java.io.PrintWriter;
88 import java.util.ArrayList;
89 import java.util.Arrays;
90 import java.util.Collections;
91 import java.util.HashSet;
92 import java.util.List;
93 import java.util.Set;
94 
95 /**
96  * This class represents an accessibility client - either an AccessibilityService or a UiAutomation.
97  * It is responsible for behavior common to both types of clients.
98  */
99 abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServiceConnection.Stub
100         implements ServiceConnection, IBinder.DeathRecipient, KeyEventDispatcher.KeyEventFilter,
101         FingerprintGestureDispatcher.FingerprintGestureClient {
102     private static final boolean DEBUG = false;
103     private static final String LOG_TAG = "AbstractAccessibilityServiceConnection";
104     private static final int WAIT_WINDOWS_TIMEOUT_MILLIS = 5000;
105 
106     protected static final String TAKE_SCREENSHOT = "takeScreenshot";
107     protected final Context mContext;
108     protected final SystemSupport mSystemSupport;
109     protected final WindowManagerInternal mWindowManagerService;
110     private final SystemActionPerformer mSystemActionPerformer;
111     private final AccessibilityWindowManager mA11yWindowManager;
112     private final DisplayManager mDisplayManager;
113     private final PowerManager mPowerManager;
114     private final IPlatformCompat mIPlatformCompat;
115 
116     private final Handler mMainHandler;
117 
118     // Handler for scheduling method invocations on the main thread.
119     public final InvocationHandler mInvocationHandler;
120 
121     final int mId;
122 
123     protected final AccessibilityServiceInfo mAccessibilityServiceInfo;
124 
125     // Lock must match the one used by AccessibilityManagerService
126     protected final Object mLock;
127 
128     protected final AccessibilitySecurityPolicy mSecurityPolicy;
129 
130     // The service that's bound to this instance. Whenever this value is non-null, this
131     // object is registered as a death recipient
132     IBinder mService;
133 
134     IAccessibilityServiceClient mServiceInterface;
135 
136     int mEventTypes;
137 
138     int mFeedbackType;
139 
140     Set<String> mPackageNames = new HashSet<>();
141 
142     boolean mIsDefault;
143 
144     boolean mRequestTouchExplorationMode;
145 
146     private boolean mServiceHandlesDoubleTap;
147 
148     private boolean mRequestMultiFingerGestures;
149 
150     boolean mRequestFilterKeyEvents;
151 
152     boolean mRetrieveInteractiveWindows;
153 
154     boolean mCaptureFingerprintGestures;
155 
156     boolean mRequestAccessibilityButton;
157 
158     boolean mReceivedAccessibilityButtonCallbackSinceBind;
159 
160     boolean mLastAccessibilityButtonCallbackState;
161 
162     int mFetchFlags;
163 
164     long mNotificationTimeout;
165 
166     final ComponentName mComponentName;
167 
168     // the events pending events to be dispatched to this service
169     final SparseArray<AccessibilityEvent> mPendingEvents = new SparseArray<>();
170 
171     /** Whether this service relies on its {@link AccessibilityCache} being up to date */
172     boolean mUsesAccessibilityCache = false;
173 
174     // Handler only for dispatching accessibility events since we use event
175     // types as message types allowing us to remove messages per event type.
176     public Handler mEventDispatchHandler;
177 
178     final SparseArray<IBinder> mOverlayWindowTokens = new SparseArray();
179 
180     /** The timestamp of requesting to take screenshot in milliseconds */
181     private long mRequestTakeScreenshotTimestampMs;
182 
183     public interface SystemSupport {
184         /**
185          * @return The current dispatcher for key events
186          */
getKeyEventDispatcher()187         @NonNull KeyEventDispatcher getKeyEventDispatcher();
188 
189         /**
190          * @param windowId The id of the window of interest
191          * @return The magnification spec for the window, or {@code null} if none is available
192          */
getCompatibleMagnificationSpecLocked(int windowId)193         @Nullable MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId);
194 
195         /**
196          * @param displayId The display id.
197          * @return The current injector of motion events used on the display, if one exists.
198          */
getMotionEventInjectorForDisplayLocked(int displayId)199         @Nullable MotionEventInjector getMotionEventInjectorForDisplayLocked(int displayId);
200 
201         /**
202          * @return The current dispatcher for fingerprint gestures, if one exists
203          */
getFingerprintGestureDispatcher()204         @Nullable FingerprintGestureDispatcher getFingerprintGestureDispatcher();
205 
206         /**
207          * @return The magnification controller
208          */
getMagnificationController()209         @NonNull MagnificationController getMagnificationController();
210 
211         /**
212          * Called back to notify system that the client has changed
213          * @param serviceInfoChanged True if the service's AccessibilityServiceInfo changed.
214          */
onClientChangeLocked(boolean serviceInfoChanged)215         void onClientChangeLocked(boolean serviceInfoChanged);
216 
getCurrentUserIdLocked()217         int getCurrentUserIdLocked();
218 
isAccessibilityButtonShown()219         boolean isAccessibilityButtonShown();
220 
221         /**
222          * Persists the component names in the specified setting in a
223          * colon separated fashion.
224          *
225          * @param settingName The setting name.
226          * @param componentNames The component names.
227          * @param userId The user id to persist the setting for.
228          */
persistComponentNamesToSettingLocked(String settingName, Set<ComponentName> componentNames, int userId)229         void persistComponentNamesToSettingLocked(String settingName,
230                 Set<ComponentName> componentNames, int userId);
231 
232         /* This is exactly PendingIntent.getActivity, separated out for testability */
getPendingIntentActivity(Context context, int requestCode, Intent intent, int flags)233         PendingIntent getPendingIntentActivity(Context context, int requestCode, Intent intent,
234                 int flags);
235 
setGestureDetectionPassthroughRegion(int displayId, Region region)236         void setGestureDetectionPassthroughRegion(int displayId, Region region);
237 
setTouchExplorationPassthroughRegion(int displayId, Region region)238         void setTouchExplorationPassthroughRegion(int displayId, Region region);
239     }
240 
AbstractAccessibilityServiceConnection(Context context, ComponentName componentName, AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler, Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport, WindowManagerInternal windowManagerInternal, SystemActionPerformer systemActionPerfomer, AccessibilityWindowManager a11yWindowManager)241     public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName,
242             AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler,
243             Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport,
244             WindowManagerInternal windowManagerInternal,
245             SystemActionPerformer systemActionPerfomer,
246             AccessibilityWindowManager a11yWindowManager) {
247         mContext = context;
248         mWindowManagerService = windowManagerInternal;
249         mId = id;
250         mComponentName = componentName;
251         mAccessibilityServiceInfo = accessibilityServiceInfo;
252         mLock = lock;
253         mSecurityPolicy = securityPolicy;
254         mSystemActionPerformer = systemActionPerfomer;
255         mSystemSupport = systemSupport;
256         mMainHandler = mainHandler;
257         mInvocationHandler = new InvocationHandler(mainHandler.getLooper());
258         mA11yWindowManager = a11yWindowManager;
259         mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
260         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
261         mIPlatformCompat = IPlatformCompat.Stub.asInterface(
262                 ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
263         mEventDispatchHandler = new Handler(mainHandler.getLooper()) {
264             @Override
265             public void handleMessage(Message message) {
266                 final int eventType =  message.what;
267                 AccessibilityEvent event = (AccessibilityEvent) message.obj;
268                 boolean serviceWantsEvent = message.arg1 != 0;
269                 notifyAccessibilityEventInternal(eventType, event, serviceWantsEvent);
270             }
271         };
272         setDynamicallyConfigurableProperties(accessibilityServiceInfo);
273     }
274 
275     @Override
onKeyEvent(KeyEvent keyEvent, int sequenceNumber)276     public boolean onKeyEvent(KeyEvent keyEvent, int sequenceNumber) {
277         if (!mRequestFilterKeyEvents || (mServiceInterface == null)) {
278             return false;
279         }
280         if((mAccessibilityServiceInfo.getCapabilities()
281                 & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) == 0) {
282             return false;
283         }
284         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
285             return false;
286         }
287         try {
288             mServiceInterface.onKeyEvent(keyEvent, sequenceNumber);
289         } catch (RemoteException e) {
290             return false;
291         }
292         return true;
293     }
294 
setDynamicallyConfigurableProperties(AccessibilityServiceInfo info)295     public void setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) {
296         mEventTypes = info.eventTypes;
297         mFeedbackType = info.feedbackType;
298         String[] packageNames = info.packageNames;
299         if (packageNames != null) {
300             mPackageNames.addAll(Arrays.asList(packageNames));
301         }
302         mNotificationTimeout = info.notificationTimeout;
303         mIsDefault = (info.flags & DEFAULT) != 0;
304 
305         if (supportsFlagForNotImportantViews(info)) {
306             if ((info.flags & AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0) {
307                 mFetchFlags |= AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
308             } else {
309                 mFetchFlags &= ~AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
310             }
311         }
312 
313         if ((info.flags & AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS) != 0) {
314             mFetchFlags |= AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS;
315         } else {
316             mFetchFlags &= ~AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS;
317         }
318 
319         mRequestTouchExplorationMode = (info.flags
320                 & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
321         mServiceHandlesDoubleTap = (info.flags
322                 & AccessibilityServiceInfo.FLAG_SERVICE_HANDLES_DOUBLE_TAP) != 0;
323         mRequestMultiFingerGestures = (info.flags
324                 & AccessibilityServiceInfo.FLAG_REQUEST_MULTI_FINGER_GESTURES) != 0;
325         mRequestFilterKeyEvents = (info.flags
326                 & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0;
327         mRetrieveInteractiveWindows = (info.flags
328                 & AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS) != 0;
329         mCaptureFingerprintGestures = (info.flags
330                 & AccessibilityServiceInfo.FLAG_REQUEST_FINGERPRINT_GESTURES) != 0;
331         mRequestAccessibilityButton = (info.flags
332                 & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
333     }
334 
supportsFlagForNotImportantViews(AccessibilityServiceInfo info)335     protected boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) {
336         return info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion
337                 >= Build.VERSION_CODES.JELLY_BEAN;
338     }
339 
canReceiveEventsLocked()340     public boolean canReceiveEventsLocked() {
341         return (mEventTypes != 0 && mService != null);
342     }
343 
344     @Override
setOnKeyEventResult(boolean handled, int sequence)345     public void setOnKeyEventResult(boolean handled, int sequence) {
346         mSystemSupport.getKeyEventDispatcher().setOnKeyEventResult(this, handled, sequence);
347     }
348 
349     @Override
getServiceInfo()350     public AccessibilityServiceInfo getServiceInfo() {
351         synchronized (mLock) {
352             return mAccessibilityServiceInfo;
353         }
354     }
355 
getCapabilities()356     public int getCapabilities() {
357         return mAccessibilityServiceInfo.getCapabilities();
358     }
359 
getRelevantEventTypes()360     int getRelevantEventTypes() {
361         return (mUsesAccessibilityCache ? AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK
362                 : AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) | mEventTypes;
363     }
364 
365     @Override
setServiceInfo(AccessibilityServiceInfo info)366     public void setServiceInfo(AccessibilityServiceInfo info) {
367         final long identity = Binder.clearCallingIdentity();
368         try {
369             synchronized (mLock) {
370                 // If the XML manifest had data to configure the service its info
371                 // should be already set. In such a case update only the dynamically
372                 // configurable properties.
373                 AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo;
374                 if (oldInfo != null) {
375                     oldInfo.updateDynamicallyConfigurableProperties(mIPlatformCompat, info);
376                     setDynamicallyConfigurableProperties(oldInfo);
377                 } else {
378                     setDynamicallyConfigurableProperties(info);
379                 }
380                 mSystemSupport.onClientChangeLocked(true);
381             }
382         } finally {
383             Binder.restoreCallingIdentity(identity);
384         }
385     }
386 
hasRightsToCurrentUserLocked()387     protected abstract boolean hasRightsToCurrentUserLocked();
388 
389     @Nullable
390     @Override
getWindows()391     public AccessibilityWindowInfo.WindowListSparseArray getWindows() {
392         synchronized (mLock) {
393             if (!hasRightsToCurrentUserLocked()) {
394                 return null;
395             }
396             final boolean permissionGranted =
397                     mSecurityPolicy.canRetrieveWindowsLocked(this);
398             if (!permissionGranted) {
399                 return null;
400             }
401             if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
402                 return null;
403             }
404             final AccessibilityWindowInfo.WindowListSparseArray allWindows =
405                     new AccessibilityWindowInfo.WindowListSparseArray();
406             final ArrayList<Integer> displayList = mA11yWindowManager.getDisplayListLocked();
407             final int displayListCounts = displayList.size();
408             if (displayListCounts > 0) {
409                 for (int i = 0; i < displayListCounts; i++) {
410                     final int displayId = displayList.get(i);
411                     ensureWindowsAvailableTimedLocked(displayId);
412 
413                     final List<AccessibilityWindowInfo> windowList = getWindowsByDisplayLocked(
414                             displayId);
415                     if (windowList != null) {
416                         allWindows.put(displayId, windowList);
417                     }
418                 }
419             }
420             return allWindows;
421         }
422     }
423 
424     @Override
getWindow(int windowId)425     public AccessibilityWindowInfo getWindow(int windowId) {
426         synchronized (mLock) {
427             int displayId = Display.INVALID_DISPLAY;
428             if (windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
429                 displayId = mA11yWindowManager.getDisplayIdByUserIdAndWindowIdLocked(
430                         mSystemSupport.getCurrentUserIdLocked(), windowId);
431             }
432             ensureWindowsAvailableTimedLocked(displayId);
433 
434             if (!hasRightsToCurrentUserLocked()) {
435                 return null;
436             }
437             final boolean permissionGranted =
438                     mSecurityPolicy.canRetrieveWindowsLocked(this);
439             if (!permissionGranted) {
440                 return null;
441             }
442             if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
443                 return null;
444             }
445             AccessibilityWindowInfo window =
446                     mA11yWindowManager.findA11yWindowInfoByIdLocked(windowId);
447             if (window != null) {
448                 AccessibilityWindowInfo windowClone = AccessibilityWindowInfo.obtain(window);
449                 windowClone.setConnectionId(mId);
450                 return windowClone;
451             }
452             return null;
453         }
454     }
455 
456     @Override
findAccessibilityNodeInfosByViewId(int accessibilityWindowId, long accessibilityNodeId, String viewIdResName, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)457     public String[] findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
458             long accessibilityNodeId, String viewIdResName, int interactionId,
459             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
460             throws RemoteException {
461         final int resolvedWindowId;
462         RemoteAccessibilityConnection connection;
463         Region partialInteractiveRegion = Region.obtain();
464         MagnificationSpec spec;
465         synchronized (mLock) {
466             mUsesAccessibilityCache = true;
467             if (!hasRightsToCurrentUserLocked()) {
468                 return null;
469             }
470             resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
471             final boolean permissionGranted =
472                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(
473                             mSystemSupport.getCurrentUserIdLocked(), this, resolvedWindowId);
474             if (!permissionGranted) {
475                 return null;
476             } else {
477                 connection = mA11yWindowManager.getConnectionLocked(
478                         mSystemSupport.getCurrentUserIdLocked(), resolvedWindowId);
479                 if (connection == null) {
480                     return null;
481                 }
482             }
483             if (!mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(
484                     resolvedWindowId, partialInteractiveRegion)) {
485                 partialInteractiveRegion.recycle();
486                 partialInteractiveRegion = null;
487             }
488             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
489         }
490         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
491             return null;
492         }
493         final int interrogatingPid = Binder.getCallingPid();
494         callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
495                 interrogatingPid, interrogatingTid);
496         final long identityToken = Binder.clearCallingIdentity();
497         try {
498             connection.getRemote().findAccessibilityNodeInfosByViewId(accessibilityNodeId,
499                     viewIdResName, partialInteractiveRegion, interactionId, callback, mFetchFlags,
500                     interrogatingPid, interrogatingTid, spec);
501             return mSecurityPolicy.computeValidReportedPackages(
502                     connection.getPackageName(), connection.getUid());
503         } catch (RemoteException re) {
504             if (DEBUG) {
505                 Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId().");
506             }
507         } finally {
508             Binder.restoreCallingIdentity(identityToken);
509             // Recycle if passed to another process.
510             if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
511                 partialInteractiveRegion.recycle();
512             }
513         }
514         return null;
515     }
516 
517     @Override
findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId, String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)518     public String[] findAccessibilityNodeInfosByText(int accessibilityWindowId,
519             long accessibilityNodeId, String text, int interactionId,
520             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
521             throws RemoteException {
522         final int resolvedWindowId;
523         RemoteAccessibilityConnection connection;
524         Region partialInteractiveRegion = Region.obtain();
525         MagnificationSpec spec;
526         synchronized (mLock) {
527             mUsesAccessibilityCache = true;
528             if (!hasRightsToCurrentUserLocked()) {
529                 return null;
530             }
531             resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
532             final boolean permissionGranted =
533                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(
534                             mSystemSupport.getCurrentUserIdLocked(), this, resolvedWindowId);
535             if (!permissionGranted) {
536                 return null;
537             } else {
538                 connection = mA11yWindowManager.getConnectionLocked(
539                         mSystemSupport.getCurrentUserIdLocked(), resolvedWindowId);
540                 if (connection == null) {
541                     return null;
542                 }
543             }
544             if (!mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(
545                     resolvedWindowId, partialInteractiveRegion)) {
546                 partialInteractiveRegion.recycle();
547                 partialInteractiveRegion = null;
548             }
549             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
550         }
551         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
552             return null;
553         }
554         final int interrogatingPid = Binder.getCallingPid();
555         callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
556                 interrogatingPid, interrogatingTid);
557         final long identityToken = Binder.clearCallingIdentity();
558         try {
559             connection.getRemote().findAccessibilityNodeInfosByText(accessibilityNodeId,
560                     text, partialInteractiveRegion, interactionId, callback, mFetchFlags,
561                     interrogatingPid, interrogatingTid, spec);
562             return mSecurityPolicy.computeValidReportedPackages(
563                     connection.getPackageName(), connection.getUid());
564         } catch (RemoteException re) {
565             if (DEBUG) {
566                 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()");
567             }
568         } finally {
569             Binder.restoreCallingIdentity(identityToken);
570             // Recycle if passed to another process.
571             if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
572                 partialInteractiveRegion.recycle();
573             }
574         }
575         return null;
576     }
577 
578     @Override
findAccessibilityNodeInfoByAccessibilityId( int accessibilityWindowId, long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, long interrogatingTid, Bundle arguments)579     public String[] findAccessibilityNodeInfoByAccessibilityId(
580             int accessibilityWindowId, long accessibilityNodeId, int interactionId,
581             IAccessibilityInteractionConnectionCallback callback, int flags,
582             long interrogatingTid, Bundle arguments) throws RemoteException {
583         final int resolvedWindowId;
584         RemoteAccessibilityConnection connection;
585         Region partialInteractiveRegion = Region.obtain();
586         MagnificationSpec spec;
587         synchronized (mLock) {
588             mUsesAccessibilityCache = true;
589             if (!hasRightsToCurrentUserLocked()) {
590                 return null;
591             }
592             resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
593             final boolean permissionGranted =
594                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(
595                             mSystemSupport.getCurrentUserIdLocked(), this, resolvedWindowId);
596             if (!permissionGranted) {
597                 return null;
598             } else {
599                 connection = mA11yWindowManager.getConnectionLocked(
600                         mSystemSupport.getCurrentUserIdLocked(), resolvedWindowId);
601                 if (connection == null) {
602                     return null;
603                 }
604             }
605             if (!mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(
606                     resolvedWindowId, partialInteractiveRegion)) {
607                 partialInteractiveRegion.recycle();
608                 partialInteractiveRegion = null;
609             }
610             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
611         }
612         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
613             return null;
614         }
615         final int interrogatingPid = Binder.getCallingPid();
616         callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
617                 interrogatingPid, interrogatingTid);
618         final long identityToken = Binder.clearCallingIdentity();
619         try {
620             connection.getRemote().findAccessibilityNodeInfoByAccessibilityId(
621                     accessibilityNodeId, partialInteractiveRegion, interactionId, callback,
622                     mFetchFlags | flags, interrogatingPid, interrogatingTid, spec, arguments);
623             return mSecurityPolicy.computeValidReportedPackages(
624                     connection.getPackageName(), connection.getUid());
625         } catch (RemoteException re) {
626             if (DEBUG) {
627                 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
628             }
629         } finally {
630             Binder.restoreCallingIdentity(identityToken);
631             // Recycle if passed to another process.
632             if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
633                 partialInteractiveRegion.recycle();
634             }
635         }
636         return null;
637     }
638 
639     @Override
findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)640     public String[] findFocus(int accessibilityWindowId, long accessibilityNodeId,
641             int focusType, int interactionId,
642             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
643             throws RemoteException {
644         final int resolvedWindowId;
645         RemoteAccessibilityConnection connection;
646         Region partialInteractiveRegion = Region.obtain();
647         MagnificationSpec spec;
648         synchronized (mLock) {
649             if (!hasRightsToCurrentUserLocked()) {
650                 return null;
651             }
652             resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked(
653                     accessibilityWindowId, focusType);
654             final boolean permissionGranted =
655                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(
656                             mSystemSupport.getCurrentUserIdLocked(), this, resolvedWindowId);
657             if (!permissionGranted) {
658                 return null;
659             } else {
660                 connection = mA11yWindowManager.getConnectionLocked(
661                         mSystemSupport.getCurrentUserIdLocked(), resolvedWindowId);
662                 if (connection == null) {
663                     return null;
664                 }
665             }
666             if (!mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(
667                     resolvedWindowId, partialInteractiveRegion)) {
668                 partialInteractiveRegion.recycle();
669                 partialInteractiveRegion = null;
670             }
671             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
672         }
673         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
674             return null;
675         }
676         final int interrogatingPid = Binder.getCallingPid();
677         callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
678                 interrogatingPid, interrogatingTid);
679         final long identityToken = Binder.clearCallingIdentity();
680         try {
681             connection.getRemote().findFocus(accessibilityNodeId, focusType,
682                     partialInteractiveRegion, interactionId, callback, mFetchFlags,
683                     interrogatingPid, interrogatingTid, spec);
684             return mSecurityPolicy.computeValidReportedPackages(
685                     connection.getPackageName(), connection.getUid());
686         } catch (RemoteException re) {
687             if (DEBUG) {
688                 Slog.e(LOG_TAG, "Error calling findFocus()");
689             }
690         } finally {
691             Binder.restoreCallingIdentity(identityToken);
692             // Recycle if passed to another process.
693             if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
694                 partialInteractiveRegion.recycle();
695             }
696         }
697         return null;
698     }
699 
700     @Override
focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)701     public String[] focusSearch(int accessibilityWindowId, long accessibilityNodeId,
702             int direction, int interactionId,
703             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
704             throws RemoteException {
705         final int resolvedWindowId;
706         RemoteAccessibilityConnection connection;
707         Region partialInteractiveRegion = Region.obtain();
708         MagnificationSpec spec;
709         synchronized (mLock) {
710             if (!hasRightsToCurrentUserLocked()) {
711                 return null;
712             }
713             resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
714             final boolean permissionGranted =
715                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(
716                             mSystemSupport.getCurrentUserIdLocked(), this, resolvedWindowId);
717             if (!permissionGranted) {
718                 return null;
719             } else {
720                 connection = mA11yWindowManager.getConnectionLocked(
721                         mSystemSupport.getCurrentUserIdLocked(), resolvedWindowId);
722                 if (connection == null) {
723                     return null;
724                 }
725             }
726             if (!mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(
727                     resolvedWindowId, partialInteractiveRegion)) {
728                 partialInteractiveRegion.recycle();
729                 partialInteractiveRegion = null;
730             }
731             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
732         }
733         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
734             return null;
735         }
736         final int interrogatingPid = Binder.getCallingPid();
737         callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
738                 interrogatingPid, interrogatingTid);
739         final long identityToken = Binder.clearCallingIdentity();
740         try {
741             connection.getRemote().focusSearch(accessibilityNodeId, direction,
742                     partialInteractiveRegion, interactionId, callback, mFetchFlags,
743                     interrogatingPid, interrogatingTid, spec);
744             return mSecurityPolicy.computeValidReportedPackages(
745                     connection.getPackageName(), connection.getUid());
746         } catch (RemoteException re) {
747             if (DEBUG) {
748                 Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()");
749             }
750         } finally {
751             Binder.restoreCallingIdentity(identityToken);
752             // Recycle if passed to another process.
753             if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
754                 partialInteractiveRegion.recycle();
755             }
756         }
757         return null;
758     }
759 
760     @Override
sendGesture(int sequence, ParceledListSlice gestureSteps)761     public void sendGesture(int sequence, ParceledListSlice gestureSteps) {
762     }
763 
764     @Override
dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId)765     public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
766     }
767 
768     @Override
performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)769     public boolean performAccessibilityAction(int accessibilityWindowId,
770             long accessibilityNodeId, int action, Bundle arguments, int interactionId,
771             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
772             throws RemoteException {
773         final int resolvedWindowId;
774         synchronized (mLock) {
775             if (!hasRightsToCurrentUserLocked()) {
776                 return false;
777             }
778             resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
779             if (!mSecurityPolicy.canGetAccessibilityNodeInfoLocked(
780                     mSystemSupport.getCurrentUserIdLocked(), this, resolvedWindowId)) {
781                 return false;
782             }
783         }
784         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
785             return false;
786         }
787         return performAccessibilityActionInternal(
788                 mSystemSupport.getCurrentUserIdLocked(), resolvedWindowId, accessibilityNodeId,
789                 action, arguments, interactionId, callback, mFetchFlags, interrogatingTid);
790     }
791 
792     @Override
performGlobalAction(int action)793     public boolean performGlobalAction(int action) {
794         synchronized (mLock) {
795             if (!hasRightsToCurrentUserLocked()) {
796                 return false;
797             }
798         }
799         return mSystemActionPerformer.performSystemAction(action);
800     }
801 
802     @Override
getSystemActions()803     public @NonNull List<AccessibilityNodeInfo.AccessibilityAction> getSystemActions() {
804         synchronized (mLock) {
805             if (!hasRightsToCurrentUserLocked()) {
806                 return Collections.emptyList();
807             }
808         }
809         return mSystemActionPerformer.getSystemActions();
810     }
811 
812     @Override
isFingerprintGestureDetectionAvailable()813     public boolean isFingerprintGestureDetectionAvailable() {
814         if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
815             return false;
816         }
817         if (isCapturingFingerprintGestures()) {
818             FingerprintGestureDispatcher dispatcher =
819                     mSystemSupport.getFingerprintGestureDispatcher();
820             return (dispatcher != null) && dispatcher.isFingerprintGestureDetectionAvailable();
821         }
822         return false;
823     }
824 
825     @Override
getMagnificationScale(int displayId)826     public float getMagnificationScale(int displayId) {
827         synchronized (mLock) {
828             if (!hasRightsToCurrentUserLocked()) {
829                 return 1.0f;
830             }
831         }
832         final long identity = Binder.clearCallingIdentity();
833         try {
834             return mSystemSupport.getMagnificationController().getScale(displayId);
835         } finally {
836             Binder.restoreCallingIdentity(identity);
837         }
838     }
839 
840     @Override
getMagnificationRegion(int displayId)841     public Region getMagnificationRegion(int displayId) {
842         synchronized (mLock) {
843             final Region region = Region.obtain();
844             if (!hasRightsToCurrentUserLocked()) {
845                 return region;
846             }
847             MagnificationController magnificationController =
848                     mSystemSupport.getMagnificationController();
849             boolean registeredJustForThisCall =
850                     registerMagnificationIfNeeded(displayId, magnificationController);
851             final long identity = Binder.clearCallingIdentity();
852             try {
853                 magnificationController.getMagnificationRegion(displayId, region);
854                 return region;
855             } finally {
856                 Binder.restoreCallingIdentity(identity);
857                 if (registeredJustForThisCall) {
858                     magnificationController.unregister(displayId);
859                 }
860             }
861         }
862     }
863 
864     @Override
getMagnificationCenterX(int displayId)865     public float getMagnificationCenterX(int displayId) {
866         synchronized (mLock) {
867             if (!hasRightsToCurrentUserLocked()) {
868                 return 0.0f;
869             }
870             MagnificationController magnificationController =
871                     mSystemSupport.getMagnificationController();
872             boolean registeredJustForThisCall =
873                     registerMagnificationIfNeeded(displayId, magnificationController);
874             final long identity = Binder.clearCallingIdentity();
875             try {
876                 return magnificationController.getCenterX(displayId);
877             } finally {
878                 Binder.restoreCallingIdentity(identity);
879                 if (registeredJustForThisCall) {
880                     magnificationController.unregister(displayId);
881                 }
882             }
883         }
884     }
885 
886     @Override
getMagnificationCenterY(int displayId)887     public float getMagnificationCenterY(int displayId) {
888         synchronized (mLock) {
889             if (!hasRightsToCurrentUserLocked()) {
890                 return 0.0f;
891             }
892             MagnificationController magnificationController =
893                     mSystemSupport.getMagnificationController();
894             boolean registeredJustForThisCall =
895                     registerMagnificationIfNeeded(displayId, magnificationController);
896             final long identity = Binder.clearCallingIdentity();
897             try {
898                 return magnificationController.getCenterY(displayId);
899             } finally {
900                 Binder.restoreCallingIdentity(identity);
901                 if (registeredJustForThisCall) {
902                     magnificationController.unregister(displayId);
903                 }
904             }
905         }
906     }
907 
registerMagnificationIfNeeded(int displayId, MagnificationController magnificationController)908     private boolean registerMagnificationIfNeeded(int displayId,
909             MagnificationController magnificationController) {
910         if (!magnificationController.isRegistered(displayId)
911                 && mSecurityPolicy.canControlMagnification(this)) {
912             magnificationController.register(displayId);
913             return true;
914         }
915         return false;
916     }
917 
918     @Override
resetMagnification(int displayId, boolean animate)919     public boolean resetMagnification(int displayId, boolean animate) {
920         synchronized (mLock) {
921             if (!hasRightsToCurrentUserLocked()) {
922                 return false;
923             }
924             if (!mSecurityPolicy.canControlMagnification(this)) {
925                 return false;
926             }
927         }
928         final long identity = Binder.clearCallingIdentity();
929         try {
930             MagnificationController magnificationController =
931                     mSystemSupport.getMagnificationController();
932             return (magnificationController.reset(displayId, animate)
933                     || !magnificationController.isMagnifying(displayId));
934         } finally {
935             Binder.restoreCallingIdentity(identity);
936         }
937     }
938 
939     @Override
setMagnificationScaleAndCenter(int displayId, float scale, float centerX, float centerY, boolean animate)940     public boolean setMagnificationScaleAndCenter(int displayId, float scale, float centerX,
941             float centerY, boolean animate) {
942         synchronized (mLock) {
943             if (!hasRightsToCurrentUserLocked()) {
944                 return false;
945             }
946             if (!mSecurityPolicy.canControlMagnification(this)) {
947                 return false;
948             }
949             final long identity = Binder.clearCallingIdentity();
950             try {
951                 MagnificationController magnificationController =
952                         mSystemSupport.getMagnificationController();
953                 if (!magnificationController.isRegistered(displayId)) {
954                     magnificationController.register(displayId);
955                 }
956                 return magnificationController
957                         .setScaleAndCenter(displayId, scale, centerX, centerY, animate, mId);
958             } finally {
959                 Binder.restoreCallingIdentity(identity);
960             }
961         }
962     }
963 
964     @Override
setMagnificationCallbackEnabled(int displayId, boolean enabled)965     public void setMagnificationCallbackEnabled(int displayId, boolean enabled) {
966         mInvocationHandler.setMagnificationCallbackEnabled(displayId, enabled);
967     }
968 
isMagnificationCallbackEnabled(int displayId)969     public boolean isMagnificationCallbackEnabled(int displayId) {
970         return mInvocationHandler.isMagnificationCallbackEnabled(displayId);
971     }
972 
973     @Override
setSoftKeyboardCallbackEnabled(boolean enabled)974     public void setSoftKeyboardCallbackEnabled(boolean enabled) {
975         mInvocationHandler.setSoftKeyboardCallbackEnabled(enabled);
976     }
977 
978     @Override
takeScreenshot(int displayId, RemoteCallback callback)979     public void takeScreenshot(int displayId, RemoteCallback callback) {
980         final long currentTimestamp = SystemClock.uptimeMillis();
981         if (mRequestTakeScreenshotTimestampMs != 0
982                 && (currentTimestamp - mRequestTakeScreenshotTimestampMs)
983                 <= AccessibilityService.ACCESSIBILITY_TAKE_SCREENSHOT_REQUEST_INTERVAL_TIMES_MS) {
984             sendScreenshotFailure(AccessibilityService.ERROR_TAKE_SCREENSHOT_INTERVAL_TIME_SHORT,
985                     callback);
986             return;
987         }
988         mRequestTakeScreenshotTimestampMs = currentTimestamp;
989 
990         synchronized (mLock) {
991             if (!hasRightsToCurrentUserLocked()) {
992                 sendScreenshotFailure(AccessibilityService.ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR,
993                         callback);
994                 return;
995             }
996 
997             if (!mSecurityPolicy.canTakeScreenshotLocked(this)) {
998                 throw new SecurityException("Services don't have the capability of taking"
999                         + " the screenshot.");
1000             }
1001         }
1002 
1003         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
1004             sendScreenshotFailure(
1005                     AccessibilityService.ERROR_TAKE_SCREENSHOT_NO_ACCESSIBILITY_ACCESS,
1006                     callback);
1007             return;
1008         }
1009 
1010         // Private virtual displays are created by the ap and is not allowed to access by other
1011         // aps.  We assume the contents on this display should not be captured.
1012         final DisplayManager displayManager =
1013                 (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
1014         final Display display = displayManager.getDisplay(displayId);
1015         if ((display == null) || (display.getType() == Display.TYPE_VIRTUAL
1016                 && (display.getFlags() & Display.FLAG_PRIVATE) != 0)) {
1017             sendScreenshotFailure(
1018                     AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY, callback);
1019             return;
1020         }
1021 
1022         final long identity = Binder.clearCallingIdentity();
1023         try {
1024             mMainHandler.post(PooledLambda.obtainRunnable((nonArg) -> {
1025                 final ScreenshotGraphicBuffer screenshotBuffer = LocalServices
1026                         .getService(DisplayManagerInternal.class).userScreenshot(displayId);
1027                 if (screenshotBuffer != null) {
1028                     sendScreenshotSuccess(screenshotBuffer, callback);
1029                 } else {
1030                     sendScreenshotFailure(
1031                             AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY, callback);
1032                 }
1033             }, null).recycleOnUse());
1034         } finally {
1035             Binder.restoreCallingIdentity(identity);
1036         }
1037     }
1038 
sendScreenshotSuccess(ScreenshotGraphicBuffer screenshotBuffer, RemoteCallback callback)1039     private void sendScreenshotSuccess(ScreenshotGraphicBuffer screenshotBuffer,
1040             RemoteCallback callback) {
1041         final GraphicBuffer graphicBuffer = screenshotBuffer.getGraphicBuffer();
1042         try (HardwareBuffer hardwareBuffer =
1043                      HardwareBuffer.createFromGraphicBuffer(graphicBuffer)) {
1044             final ParcelableColorSpace colorSpace =
1045                     new ParcelableColorSpace(screenshotBuffer.getColorSpace());
1046 
1047             final Bundle payload = new Bundle();
1048             payload.putInt(KEY_ACCESSIBILITY_SCREENSHOT_STATUS,
1049                     AccessibilityService.TAKE_SCREENSHOT_SUCCESS);
1050             payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER,
1051                     hardwareBuffer);
1052             payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE, colorSpace);
1053             payload.putLong(KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP,
1054                     SystemClock.uptimeMillis());
1055 
1056             // Send back the result.
1057             callback.sendResult(payload);
1058             hardwareBuffer.close();
1059         }
1060     }
1061 
sendScreenshotFailure(@ccessibilityService.ScreenshotErrorCode int errorCode, RemoteCallback callback)1062     private void sendScreenshotFailure(@AccessibilityService.ScreenshotErrorCode int errorCode,
1063             RemoteCallback callback) {
1064         mMainHandler.post(PooledLambda.obtainRunnable((nonArg) -> {
1065             final Bundle payload = new Bundle();
1066             payload.putInt(KEY_ACCESSIBILITY_SCREENSHOT_STATUS, errorCode);
1067             // Send back the result.
1068             callback.sendResult(payload);
1069         }, null).recycleOnUse());
1070     }
1071 
1072     @Override
dump(FileDescriptor fd, final PrintWriter pw, String[] args)1073     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
1074         if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
1075         synchronized (mLock) {
1076             pw.append("Service[label=" + mAccessibilityServiceInfo.getResolveInfo()
1077                     .loadLabel(mContext.getPackageManager()));
1078             pw.append(", feedbackType"
1079                     + AccessibilityServiceInfo.feedbackTypeToString(mFeedbackType));
1080             pw.append(", capabilities=" + mAccessibilityServiceInfo.getCapabilities());
1081             pw.append(", eventTypes="
1082                     + AccessibilityEvent.eventTypeToString(mEventTypes));
1083             pw.append(", notificationTimeout=" + mNotificationTimeout);
1084             pw.append(", requestA11yBtn=" + mRequestAccessibilityButton);
1085             pw.append("]");
1086         }
1087     }
1088 
onAdded()1089     public void onAdded() {
1090         final Display[] displays = mDisplayManager.getDisplays();
1091         for (int i = 0; i < displays.length; i++) {
1092             final int displayId = displays[i].getDisplayId();
1093             onDisplayAdded(displayId);
1094         }
1095     }
1096 
1097     /**
1098      * Called whenever a logical display has been added to the system. Add a window token for adding
1099      * an accessibility overlay.
1100      *
1101      * @param displayId The id of the logical display that was added.
1102      */
onDisplayAdded(int displayId)1103     public void onDisplayAdded(int displayId) {
1104         final long identity = Binder.clearCallingIdentity();
1105         try {
1106             final IBinder overlayWindowToken = new Binder();
1107             mWindowManagerService.addWindowToken(overlayWindowToken, TYPE_ACCESSIBILITY_OVERLAY,
1108                     displayId);
1109             synchronized (mLock) {
1110                 mOverlayWindowTokens.put(displayId, overlayWindowToken);
1111             }
1112         } finally {
1113             Binder.restoreCallingIdentity(identity);
1114         }
1115     }
1116 
onRemoved()1117     public void onRemoved() {
1118         final Display[] displays = mDisplayManager.getDisplays();
1119         for (int i = 0; i < displays.length; i++) {
1120             final int displayId = displays[i].getDisplayId();
1121             onDisplayRemoved(displayId);
1122         }
1123     }
1124 
1125     /**
1126      * Called whenever a logical display has been removed from the system. Remove a window token for
1127      * removing an accessibility overlay.
1128      *
1129      * @param displayId The id of the logical display that was added.
1130      */
onDisplayRemoved(int displayId)1131     public void onDisplayRemoved(int displayId) {
1132         final long identity = Binder.clearCallingIdentity();
1133         try {
1134             mWindowManagerService.removeWindowToken(mOverlayWindowTokens.get(displayId), true,
1135                     displayId);
1136             synchronized (mLock) {
1137                 mOverlayWindowTokens.remove(displayId);
1138             }
1139         } finally {
1140             Binder.restoreCallingIdentity(identity);
1141         }
1142     }
1143 
1144     /**
1145      * Gets overlay window token by the display Id.
1146      *
1147      * @param displayId The id of the logical display that was added.
1148      * @return window token.
1149      */
1150     @Override
getOverlayWindowToken(int displayId)1151     public IBinder getOverlayWindowToken(int displayId) {
1152         synchronized (mLock) {
1153             return mOverlayWindowTokens.get(displayId);
1154         }
1155     }
1156 
1157     /**
1158      * Gets windowId of given token.
1159      *
1160      * @param token The token
1161      * @return window id
1162      */
1163     @Override
getWindowIdForLeashToken(@onNull IBinder token)1164     public int getWindowIdForLeashToken(@NonNull IBinder token) {
1165         synchronized (mLock) {
1166             return mA11yWindowManager.getWindowIdLocked(token);
1167         }
1168     }
1169 
resetLocked()1170     public void resetLocked() {
1171         mSystemSupport.getKeyEventDispatcher().flush(this);
1172         try {
1173             // Clear the proxy in the other process so this
1174             // IAccessibilityServiceConnection can be garbage collected.
1175             if (mServiceInterface != null) {
1176                 mServiceInterface.init(null, mId, null);
1177             }
1178         } catch (RemoteException re) {
1179                 /* ignore */
1180         }
1181         if (mService != null) {
1182             mService.unlinkToDeath(this, 0);
1183             mService = null;
1184         }
1185 
1186         mServiceInterface = null;
1187         mReceivedAccessibilityButtonCallbackSinceBind = false;
1188     }
1189 
isConnectedLocked()1190     public boolean isConnectedLocked() {
1191         return (mService != null);
1192     }
1193 
notifyAccessibilityEvent(AccessibilityEvent event)1194     public void notifyAccessibilityEvent(AccessibilityEvent event) {
1195         synchronized (mLock) {
1196             final int eventType = event.getEventType();
1197 
1198             final boolean serviceWantsEvent = wantsEventLocked(event);
1199             final boolean requiredForCacheConsistency = mUsesAccessibilityCache
1200                     && ((AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK & eventType) != 0);
1201             if (!serviceWantsEvent && !requiredForCacheConsistency) {
1202                 return;
1203             }
1204 
1205             if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
1206                 return;
1207             }
1208             // Make a copy since during dispatch it is possible the event to
1209             // be modified to remove its source if the receiving service does
1210             // not have permission to access the window content.
1211             AccessibilityEvent newEvent = AccessibilityEvent.obtain(event);
1212             Message message;
1213             if ((mNotificationTimeout > 0)
1214                     && (eventType != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED)) {
1215                 // Allow at most one pending event
1216                 final AccessibilityEvent oldEvent = mPendingEvents.get(eventType);
1217                 mPendingEvents.put(eventType, newEvent);
1218                 if (oldEvent != null) {
1219                     mEventDispatchHandler.removeMessages(eventType);
1220                     oldEvent.recycle();
1221                 }
1222                 message = mEventDispatchHandler.obtainMessage(eventType);
1223             } else {
1224                 // Send all messages, bypassing mPendingEvents
1225                 message = mEventDispatchHandler.obtainMessage(eventType, newEvent);
1226             }
1227             message.arg1 = serviceWantsEvent ? 1 : 0;
1228 
1229             mEventDispatchHandler.sendMessageDelayed(message, mNotificationTimeout);
1230         }
1231     }
1232 
1233     /**
1234      * Determines if given event can be dispatched to a service based on the package of the
1235      * event source. Specifically, a service is notified if it is interested in events from the
1236      * package.
1237      *
1238      * @param event The event.
1239      * @return True if the listener should be notified, false otherwise.
1240      */
wantsEventLocked(AccessibilityEvent event)1241     private boolean wantsEventLocked(AccessibilityEvent event) {
1242 
1243         if (!canReceiveEventsLocked()) {
1244             return false;
1245         }
1246 
1247         if ((event.getWindowId() != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID)
1248                 && !event.isImportantForAccessibility()
1249                 && (mFetchFlags & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) {
1250             return false;
1251         }
1252 
1253         int eventType = event.getEventType();
1254         if ((mEventTypes & eventType) != eventType) {
1255             return false;
1256         }
1257 
1258         Set<String> packageNames = mPackageNames;
1259         String packageName = (event.getPackageName() != null)
1260                 ? event.getPackageName().toString() : null;
1261 
1262         return (packageNames.isEmpty() || packageNames.contains(packageName));
1263     }
1264 
1265     /**
1266      * Notifies an accessibility service client for a scheduled event given the event type.
1267      *
1268      * @param eventType The type of the event to dispatch.
1269      */
notifyAccessibilityEventInternal( int eventType, AccessibilityEvent event, boolean serviceWantsEvent)1270     private void notifyAccessibilityEventInternal(
1271             int eventType,
1272             AccessibilityEvent event,
1273             boolean serviceWantsEvent) {
1274         IAccessibilityServiceClient listener;
1275 
1276         synchronized (mLock) {
1277             listener = mServiceInterface;
1278 
1279             // If the service died/was disabled while the message for dispatching
1280             // the accessibility event was propagating the listener may be null.
1281             if (listener == null) {
1282                 return;
1283             }
1284 
1285             // There are two ways we notify for events, throttled AND non-throttled. If we
1286             // are not throttling, then messages come with events, which we handle with
1287             // minimal fuss.
1288             if (event == null) {
1289                 // We are throttling events, so we'll send the event for this type in
1290                 // mPendingEvents as long as it it's null. It can only null due to a race
1291                 // condition:
1292                 //
1293                 //   1) A binder thread calls notifyAccessibilityServiceDelayedLocked
1294                 //      which posts a message for dispatching an event and stores the event
1295                 //      in mPendingEvents.
1296                 //   2) The message is pulled from the queue by the handler on the service
1297                 //      thread and this method is just about to acquire the lock.
1298                 //   3) Another binder thread acquires the lock in notifyAccessibilityEvent
1299                 //   4) notifyAccessibilityEvent recycles the event that this method was about
1300                 //      to process, replaces it with a new one, and posts a second message
1301                 //   5) This method grabs the new event, processes it, and removes it from
1302                 //      mPendingEvents
1303                 //   6) The second message dispatched in (4) arrives, but the event has been
1304                 //      remvoved in (5).
1305                 event = mPendingEvents.get(eventType);
1306                 if (event == null) {
1307                     return;
1308                 }
1309                 mPendingEvents.remove(eventType);
1310             }
1311             if (mSecurityPolicy.canRetrieveWindowContentLocked(this)) {
1312                 event.setConnectionId(mId);
1313             } else {
1314                 event.setSource((View) null);
1315             }
1316             event.setSealed(true);
1317         }
1318 
1319         try {
1320             listener.onAccessibilityEvent(event, serviceWantsEvent);
1321             if (DEBUG) {
1322                 Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
1323             }
1324         } catch (RemoteException re) {
1325             Slog.e(LOG_TAG, "Error during sending " + event + " to " + listener, re);
1326         } finally {
1327             event.recycle();
1328         }
1329     }
1330 
notifyGesture(AccessibilityGestureEvent gestureEvent)1331     public void notifyGesture(AccessibilityGestureEvent gestureEvent) {
1332         mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_GESTURE,
1333                 gestureEvent).sendToTarget();
1334     }
1335 
notifySystemActionsChangedLocked()1336     public void notifySystemActionsChangedLocked() {
1337         mInvocationHandler.sendEmptyMessage(
1338                 InvocationHandler.MSG_ON_SYSTEM_ACTIONS_CHANGED);
1339     }
1340 
notifyClearAccessibilityNodeInfoCache()1341     public void notifyClearAccessibilityNodeInfoCache() {
1342         mInvocationHandler.sendEmptyMessage(
1343                 InvocationHandler.MSG_CLEAR_ACCESSIBILITY_CACHE);
1344     }
1345 
notifyMagnificationChangedLocked(int displayId, @NonNull Region region, float scale, float centerX, float centerY)1346     public void notifyMagnificationChangedLocked(int displayId, @NonNull Region region,
1347             float scale, float centerX, float centerY) {
1348         mInvocationHandler
1349                 .notifyMagnificationChangedLocked(displayId, region, scale, centerX, centerY);
1350     }
1351 
notifySoftKeyboardShowModeChangedLocked(int showState)1352     public void notifySoftKeyboardShowModeChangedLocked(int showState) {
1353         mInvocationHandler.notifySoftKeyboardShowModeChangedLocked(showState);
1354     }
1355 
notifyAccessibilityButtonClickedLocked(int displayId)1356     public void notifyAccessibilityButtonClickedLocked(int displayId) {
1357         mInvocationHandler.notifyAccessibilityButtonClickedLocked(displayId);
1358     }
1359 
notifyAccessibilityButtonAvailabilityChangedLocked(boolean available)1360     public void notifyAccessibilityButtonAvailabilityChangedLocked(boolean available) {
1361         mInvocationHandler.notifyAccessibilityButtonAvailabilityChangedLocked(available);
1362     }
1363 
1364     /**
1365      * Called by the invocation handler to notify the service that the
1366      * state of magnification has changed.
1367      */
notifyMagnificationChangedInternal(int displayId, @NonNull Region region, float scale, float centerX, float centerY)1368     private void notifyMagnificationChangedInternal(int displayId, @NonNull Region region,
1369             float scale, float centerX, float centerY) {
1370         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
1371         if (listener != null) {
1372             try {
1373                 listener.onMagnificationChanged(displayId, region, scale, centerX, centerY);
1374             } catch (RemoteException re) {
1375                 Slog.e(LOG_TAG, "Error sending magnification changes to " + mService, re);
1376             }
1377         }
1378     }
1379 
1380     /**
1381      * Called by the invocation handler to notify the service that the state of the soft
1382      * keyboard show mode has changed.
1383      */
notifySoftKeyboardShowModeChangedInternal(int showState)1384     private void notifySoftKeyboardShowModeChangedInternal(int showState) {
1385         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
1386         if (listener != null) {
1387             try {
1388                 listener.onSoftKeyboardShowModeChanged(showState);
1389             } catch (RemoteException re) {
1390                 Slog.e(LOG_TAG, "Error sending soft keyboard show mode changes to " + mService,
1391                         re);
1392             }
1393         }
1394     }
1395 
notifyAccessibilityButtonClickedInternal(int displayId)1396     private void notifyAccessibilityButtonClickedInternal(int displayId) {
1397         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
1398         if (listener != null) {
1399             try {
1400                 listener.onAccessibilityButtonClicked(displayId);
1401             } catch (RemoteException re) {
1402                 Slog.e(LOG_TAG, "Error sending accessibility button click to " + mService, re);
1403             }
1404         }
1405     }
1406 
notifyAccessibilityButtonAvailabilityChangedInternal(boolean available)1407     private void notifyAccessibilityButtonAvailabilityChangedInternal(boolean available) {
1408         // Only notify the service if it's not been notified or the state has changed
1409         if (mReceivedAccessibilityButtonCallbackSinceBind
1410                 && (mLastAccessibilityButtonCallbackState == available)) {
1411             return;
1412         }
1413         mReceivedAccessibilityButtonCallbackSinceBind = true;
1414         mLastAccessibilityButtonCallbackState = available;
1415         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
1416         if (listener != null) {
1417             try {
1418                 listener.onAccessibilityButtonAvailabilityChanged(available);
1419             } catch (RemoteException re) {
1420                 Slog.e(LOG_TAG,
1421                         "Error sending accessibility button availability change to " + mService,
1422                         re);
1423             }
1424         }
1425     }
1426 
notifyGestureInternal(AccessibilityGestureEvent gestureInfo)1427     private void notifyGestureInternal(AccessibilityGestureEvent gestureInfo) {
1428         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
1429         if (listener != null) {
1430             try {
1431                 listener.onGesture(gestureInfo);
1432             } catch (RemoteException re) {
1433                 Slog.e(LOG_TAG, "Error during sending gesture " + gestureInfo
1434                         + " to " + mService, re);
1435             }
1436         }
1437     }
1438 
notifySystemActionsChangedInternal()1439     private void notifySystemActionsChangedInternal() {
1440         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
1441         if (listener != null) {
1442             try {
1443                 listener.onSystemActionsChanged();
1444             } catch (RemoteException re) {
1445                 Slog.e(LOG_TAG, "Error sending system actions change to " + mService,
1446                         re);
1447             }
1448         }
1449     }
1450 
notifyClearAccessibilityCacheInternal()1451     private void notifyClearAccessibilityCacheInternal() {
1452         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
1453         if (listener != null) {
1454             try {
1455                 listener.clearAccessibilityCache();
1456             } catch (RemoteException re) {
1457                 Slog.e(LOG_TAG, "Error during requesting accessibility info cache"
1458                         + " to be cleared.", re);
1459             }
1460         }
1461     }
1462 
getServiceInterfaceSafely()1463     private IAccessibilityServiceClient getServiceInterfaceSafely() {
1464         synchronized (mLock) {
1465             return mServiceInterface;
1466         }
1467     }
1468 
resolveAccessibilityWindowIdLocked(int accessibilityWindowId)1469     private int resolveAccessibilityWindowIdLocked(int accessibilityWindowId) {
1470         if (accessibilityWindowId == AccessibilityWindowInfo.ACTIVE_WINDOW_ID) {
1471             return mA11yWindowManager.getActiveWindowId(mSystemSupport.getCurrentUserIdLocked());
1472         }
1473         return accessibilityWindowId;
1474     }
1475 
resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType)1476     private int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) {
1477         if (windowId == AccessibilityWindowInfo.ACTIVE_WINDOW_ID) {
1478             return mA11yWindowManager.getActiveWindowId(mSystemSupport.getCurrentUserIdLocked());
1479         }
1480         if (windowId == AccessibilityWindowInfo.ANY_WINDOW_ID) {
1481             return mA11yWindowManager.getFocusedWindowId(focusType);
1482         }
1483         return windowId;
1484     }
1485 
1486     /**
1487      * Request that the system make sure windows are available to interrogate.
1488      *
1489      * @param displayId The logical display id.
1490      */
ensureWindowsAvailableTimedLocked(int displayId)1491     private void ensureWindowsAvailableTimedLocked(int displayId) {
1492         if (mA11yWindowManager.getWindowListLocked(displayId) != null) {
1493             return;
1494         }
1495         // If we have no registered callback, update the state we
1496         // we may have to register one but it didn't happen yet.
1497         if (!mA11yWindowManager.isTrackingWindowsLocked(displayId)) {
1498             // Invokes client change to make sure tracking window enabled.
1499             mSystemSupport.onClientChangeLocked(false);
1500         }
1501         // We have no windows but do not care about them, done.
1502         if (!mA11yWindowManager.isTrackingWindowsLocked(displayId)) {
1503             return;
1504         }
1505 
1506         // Wait for the windows with a timeout.
1507         final long startMillis = SystemClock.uptimeMillis();
1508         while (mA11yWindowManager.getWindowListLocked(displayId) == null) {
1509             final long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
1510             final long remainMillis = WAIT_WINDOWS_TIMEOUT_MILLIS - elapsedMillis;
1511             if (remainMillis <= 0) {
1512                 return;
1513             }
1514             try {
1515                 mLock.wait(remainMillis);
1516             } catch (InterruptedException ie) {
1517                 /* ignore */
1518             }
1519         }
1520     }
1521 
1522     /**
1523      * Perform the specified accessibility action
1524      *
1525      * @param resolvedWindowId The window ID
1526      * [Other parameters match the method on IAccessibilityServiceConnection]
1527      *
1528      * @return Whether or not the action could be sent to the app process
1529      */
performAccessibilityActionInternal(int userId, int resolvedWindowId, long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, int fetchFlags, long interrogatingTid)1530     private boolean performAccessibilityActionInternal(int userId, int resolvedWindowId,
1531             long accessibilityNodeId, int action, Bundle arguments, int interactionId,
1532             IAccessibilityInteractionConnectionCallback callback, int fetchFlags,
1533             long interrogatingTid) {
1534         RemoteAccessibilityConnection connection;
1535         IBinder activityToken = null;
1536         synchronized (mLock) {
1537             connection = mA11yWindowManager.getConnectionLocked(userId, resolvedWindowId);
1538             if (connection == null)  {
1539                 return false;
1540             }
1541             final boolean isA11yFocusAction = (action == ACTION_ACCESSIBILITY_FOCUS)
1542                     || (action == ACTION_CLEAR_ACCESSIBILITY_FOCUS);
1543             if (!isA11yFocusAction) {
1544                 final WindowInfo windowInfo =
1545                         mA11yWindowManager.findWindowInfoByIdLocked(resolvedWindowId);
1546                 if (windowInfo != null) activityToken = windowInfo.activityToken;
1547             }
1548             final AccessibilityWindowInfo a11yWindowInfo =
1549                     mA11yWindowManager.findA11yWindowInfoByIdLocked(resolvedWindowId);
1550             if (a11yWindowInfo != null && a11yWindowInfo.isInPictureInPictureMode()
1551                     && mA11yWindowManager.getPictureInPictureActionReplacingConnection() != null
1552                     && !isA11yFocusAction) {
1553                 connection = mA11yWindowManager.getPictureInPictureActionReplacingConnection();
1554             }
1555         }
1556         final int interrogatingPid = Binder.getCallingPid();
1557         final long identityToken = Binder.clearCallingIdentity();
1558         try {
1559             // Regardless of whether or not the action succeeds, it was generated by an
1560             // accessibility service that is driven by user actions, so note user activity.
1561             mPowerManager.userActivity(SystemClock.uptimeMillis(),
1562                     PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY, 0);
1563 
1564             if (action == ACTION_CLICK || action == ACTION_LONG_CLICK) {
1565                 mA11yWindowManager.notifyOutsideTouch(userId, resolvedWindowId);
1566             }
1567             if (activityToken != null) {
1568                 LocalServices.getService(ActivityTaskManagerInternal.class)
1569                         .setFocusedActivity(activityToken);
1570             }
1571             connection.getRemote().performAccessibilityAction(accessibilityNodeId, action,
1572                     arguments, interactionId, callback, fetchFlags, interrogatingPid,
1573                     interrogatingTid);
1574         } catch (RemoteException re) {
1575             if (DEBUG) {
1576                 Slog.e(LOG_TAG, "Error calling performAccessibilityAction: " + re);
1577             }
1578             return false;
1579         } finally {
1580             Binder.restoreCallingIdentity(identityToken);
1581         }
1582         return true;
1583     }
1584 
1585     /**
1586      * Replace the interaction callback if needed, for example if the window is in picture-
1587      * in-picture mode and needs its nodes replaced.
1588      *
1589      * @param originalCallback The callback we were planning to use
1590      * @param resolvedWindowId The ID of the window we're calling
1591      * @param interactionId The id for the original callback
1592      * @param interrogatingPid Process ID of requester
1593      * @param interrogatingTid Thread ID of requester
1594      *
1595      * @return The callback to use, which may be the original one.
1596      */
replaceCallbackIfNeeded( IAccessibilityInteractionConnectionCallback originalCallback, int resolvedWindowId, int interactionId, int interrogatingPid, long interrogatingTid)1597     private IAccessibilityInteractionConnectionCallback replaceCallbackIfNeeded(
1598             IAccessibilityInteractionConnectionCallback originalCallback, int resolvedWindowId,
1599             int interactionId, int interrogatingPid, long interrogatingTid) {
1600         final RemoteAccessibilityConnection pipActionReplacingConnection =
1601                 mA11yWindowManager.getPictureInPictureActionReplacingConnection();
1602         synchronized (mLock) {
1603             final AccessibilityWindowInfo windowInfo =
1604                     mA11yWindowManager.findA11yWindowInfoByIdLocked(resolvedWindowId);
1605             if ((windowInfo == null) || !windowInfo.isInPictureInPictureMode()
1606                 || (pipActionReplacingConnection == null)) {
1607                 return originalCallback;
1608             }
1609         }
1610         return new ActionReplacingCallback(originalCallback,
1611                 pipActionReplacingConnection.getRemote(), interactionId,
1612                 interrogatingPid, interrogatingTid);
1613     }
1614 
getWindowsByDisplayLocked(int displayId)1615     private List<AccessibilityWindowInfo> getWindowsByDisplayLocked(int displayId) {
1616         final List<AccessibilityWindowInfo> internalWindowList =
1617                 mA11yWindowManager.getWindowListLocked(displayId);
1618         if (internalWindowList == null) {
1619             return null;
1620         }
1621         final List<AccessibilityWindowInfo> returnedWindowList = new ArrayList<>();
1622         final int windowCount = internalWindowList.size();
1623         for (int i = 0; i < windowCount; i++) {
1624             AccessibilityWindowInfo window = internalWindowList.get(i);
1625             AccessibilityWindowInfo windowClone =
1626                     AccessibilityWindowInfo.obtain(window);
1627             windowClone.setConnectionId(mId);
1628             returnedWindowList.add(windowClone);
1629         }
1630         return returnedWindowList;
1631     }
1632 
getComponentName()1633     public ComponentName getComponentName() {
1634         return mComponentName;
1635     }
1636 
1637     private final class InvocationHandler extends Handler {
1638         public static final int MSG_ON_GESTURE = 1;
1639         public static final int MSG_CLEAR_ACCESSIBILITY_CACHE = 2;
1640 
1641         private static final int MSG_ON_MAGNIFICATION_CHANGED = 5;
1642         private static final int MSG_ON_SOFT_KEYBOARD_STATE_CHANGED = 6;
1643         private static final int MSG_ON_ACCESSIBILITY_BUTTON_CLICKED = 7;
1644         private static final int MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 8;
1645         private static final int MSG_ON_SYSTEM_ACTIONS_CHANGED = 9;
1646 
1647         /** List of magnification callback states, mapping from displayId -> Boolean */
1648         @GuardedBy("mlock")
1649         private final SparseArray<Boolean> mMagnificationCallbackState = new SparseArray<>(0);
1650         private boolean mIsSoftKeyboardCallbackEnabled = false;
1651 
InvocationHandler(Looper looper)1652         public InvocationHandler(Looper looper) {
1653             super(looper, null, true);
1654         }
1655 
1656         @Override
handleMessage(Message message)1657         public void handleMessage(Message message) {
1658             final int type = message.what;
1659             switch (type) {
1660                 case MSG_ON_GESTURE: {
1661                     notifyGestureInternal((AccessibilityGestureEvent) message.obj);
1662                 } break;
1663 
1664                 case MSG_CLEAR_ACCESSIBILITY_CACHE: {
1665                     notifyClearAccessibilityCacheInternal();
1666                 } break;
1667 
1668                 case MSG_ON_MAGNIFICATION_CHANGED: {
1669                     final SomeArgs args = (SomeArgs) message.obj;
1670                     final Region region = (Region) args.arg1;
1671                     final float scale = (float) args.arg2;
1672                     final float centerX = (float) args.arg3;
1673                     final float centerY = (float) args.arg4;
1674                     final int displayId = args.argi1;
1675                     notifyMagnificationChangedInternal(displayId, region, scale, centerX, centerY);
1676                     args.recycle();
1677                 } break;
1678 
1679                 case MSG_ON_SOFT_KEYBOARD_STATE_CHANGED: {
1680                     final int showState = (int) message.arg1;
1681                     notifySoftKeyboardShowModeChangedInternal(showState);
1682                 } break;
1683 
1684                 case MSG_ON_ACCESSIBILITY_BUTTON_CLICKED: {
1685                     final int displayId = (int) message.arg1;
1686                     notifyAccessibilityButtonClickedInternal(displayId);
1687                 } break;
1688 
1689                 case MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED: {
1690                     final boolean available = (message.arg1 != 0);
1691                     notifyAccessibilityButtonAvailabilityChangedInternal(available);
1692                 } break;
1693                 case MSG_ON_SYSTEM_ACTIONS_CHANGED: {
1694                     notifySystemActionsChangedInternal();
1695                     break;
1696                 }
1697                 default: {
1698                     throw new IllegalArgumentException("Unknown message: " + type);
1699                 }
1700             }
1701         }
1702 
notifyMagnificationChangedLocked(int displayId, @NonNull Region region, float scale, float centerX, float centerY)1703         public void notifyMagnificationChangedLocked(int displayId, @NonNull Region region,
1704                 float scale, float centerX, float centerY) {
1705             synchronized (mLock) {
1706                 if (mMagnificationCallbackState.get(displayId) == null) {
1707                     return;
1708                 }
1709             }
1710 
1711             final SomeArgs args = SomeArgs.obtain();
1712             args.arg1 = region;
1713             args.arg2 = scale;
1714             args.arg3 = centerX;
1715             args.arg4 = centerY;
1716             args.argi1 = displayId;
1717 
1718             final Message msg = obtainMessage(MSG_ON_MAGNIFICATION_CHANGED, args);
1719             msg.sendToTarget();
1720         }
1721 
setMagnificationCallbackEnabled(int displayId, boolean enabled)1722         public void setMagnificationCallbackEnabled(int displayId, boolean enabled) {
1723             synchronized (mLock) {
1724                 if (enabled) {
1725                     mMagnificationCallbackState.put(displayId, true);
1726                 } else {
1727                     mMagnificationCallbackState.remove(displayId);
1728                 }
1729             }
1730         }
1731 
isMagnificationCallbackEnabled(int displayId)1732         public boolean isMagnificationCallbackEnabled(int displayId) {
1733             synchronized (mLock) {
1734                 return mMagnificationCallbackState.get(displayId) != null;
1735             }
1736         }
1737 
notifySoftKeyboardShowModeChangedLocked(int showState)1738         public void notifySoftKeyboardShowModeChangedLocked(int showState) {
1739             if (!mIsSoftKeyboardCallbackEnabled) {
1740                 return;
1741             }
1742 
1743             final Message msg = obtainMessage(MSG_ON_SOFT_KEYBOARD_STATE_CHANGED, showState, 0);
1744             msg.sendToTarget();
1745         }
1746 
setSoftKeyboardCallbackEnabled(boolean enabled)1747         public void setSoftKeyboardCallbackEnabled(boolean enabled) {
1748             mIsSoftKeyboardCallbackEnabled = enabled;
1749         }
1750 
notifyAccessibilityButtonClickedLocked(int displayId)1751         public void notifyAccessibilityButtonClickedLocked(int displayId) {
1752             final Message msg = obtainMessage(MSG_ON_ACCESSIBILITY_BUTTON_CLICKED, displayId, 0);
1753             msg.sendToTarget();
1754         }
1755 
notifyAccessibilityButtonAvailabilityChangedLocked(boolean available)1756         public void notifyAccessibilityButtonAvailabilityChangedLocked(boolean available) {
1757             final Message msg = obtainMessage(MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED,
1758                     (available ? 1 : 0), 0);
1759             msg.sendToTarget();
1760         }
1761     }
1762 
isServiceHandlesDoubleTapEnabled()1763     public boolean isServiceHandlesDoubleTapEnabled() {
1764         return mServiceHandlesDoubleTap;
1765     }
1766 
isMultiFingerGesturesEnabled()1767     public boolean isMultiFingerGesturesEnabled() {
1768         return mRequestMultiFingerGestures;
1769     }
1770 
1771     @Override
setGestureDetectionPassthroughRegion(int displayId, Region region)1772     public void setGestureDetectionPassthroughRegion(int displayId, Region region) {
1773         mSystemSupport.setGestureDetectionPassthroughRegion(displayId, region);
1774     }
1775 
1776     @Override
setTouchExplorationPassthroughRegion(int displayId, Region region)1777     public void setTouchExplorationPassthroughRegion(int displayId, Region region) {
1778         mSystemSupport.setTouchExplorationPassthroughRegion(displayId, region);
1779     }
1780 }
1781