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