• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  ** Copyright 2009, The Android Open Source Project
3  **
4  ** Licensed under the Apache License, Version 2.0 (the "License");
5  ** you may not use this file except in compliance with the License.
6  ** You may obtain a copy of the License at
7  **
8  **     http://www.apache.org/licenses/LICENSE-2.0
9  **
10  ** Unless required by applicable law or agreed to in writing, software
11  ** distributed under the License is distributed on an "AS IS" BASIS,
12  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  ** See the License for the specific language governing permissions and
14  ** limitations under the License.
15  */
16 
17 package com.android.server.accessibility;
18 
19 import static android.accessibilityservice.AccessibilityServiceInfo.DEFAULT;
20 
21 import android.Manifest;
22 import android.accessibilityservice.AccessibilityService;
23 import android.accessibilityservice.AccessibilityServiceInfo;
24 import android.accessibilityservice.IAccessibilityServiceClient;
25 import android.accessibilityservice.IAccessibilityServiceConnection;
26 import android.app.AlertDialog;
27 import android.app.PendingIntent;
28 import android.app.StatusBarManager;
29 import android.content.BroadcastReceiver;
30 import android.content.ComponentName;
31 import android.content.ContentResolver;
32 import android.content.Context;
33 import android.content.DialogInterface;
34 import android.content.DialogInterface.OnClickListener;
35 import android.content.Intent;
36 import android.content.IntentFilter;
37 import android.content.ServiceConnection;
38 import android.content.pm.PackageManager;
39 import android.content.pm.ResolveInfo;
40 import android.content.pm.ServiceInfo;
41 import android.content.pm.UserInfo;
42 import android.database.ContentObserver;
43 import android.graphics.Point;
44 import android.graphics.Rect;
45 import android.graphics.Region;
46 import android.hardware.display.DisplayManager;
47 import android.hardware.input.InputManager;
48 import android.net.Uri;
49 import android.os.Binder;
50 import android.os.Build;
51 import android.os.Bundle;
52 import android.os.Handler;
53 import android.os.IBinder;
54 import android.os.Looper;
55 import android.os.Message;
56 import android.os.Process;
57 import android.os.RemoteCallbackList;
58 import android.os.RemoteException;
59 import android.os.ServiceManager;
60 import android.os.SystemClock;
61 import android.os.UserHandle;
62 import android.os.UserManager;
63 import android.provider.Settings;
64 import android.text.TextUtils;
65 import android.text.TextUtils.SimpleStringSplitter;
66 import android.util.Pools.Pool;
67 import android.util.Pools.SimplePool;
68 import android.util.Slog;
69 import android.util.SparseArray;
70 import android.view.Display;
71 import android.view.IWindow;
72 import android.view.InputDevice;
73 import android.view.InputEventConsistencyVerifier;
74 import android.view.KeyCharacterMap;
75 import android.view.KeyEvent;
76 import android.view.MagnificationSpec;
77 import android.view.WindowInfo;
78 import android.view.WindowManager;
79 import android.view.WindowManagerInternal;
80 import android.view.WindowManagerPolicy;
81 import android.view.accessibility.AccessibilityEvent;
82 import android.view.accessibility.AccessibilityInteractionClient;
83 import android.view.accessibility.AccessibilityManager;
84 import android.view.accessibility.AccessibilityNodeInfo;
85 import android.view.accessibility.AccessibilityWindowInfo;
86 import android.view.accessibility.IAccessibilityInteractionConnection;
87 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
88 import android.view.accessibility.IAccessibilityManager;
89 import android.view.accessibility.IAccessibilityManagerClient;
90 
91 import com.android.internal.R;
92 import com.android.internal.content.PackageMonitor;
93 import com.android.internal.statusbar.IStatusBarService;
94 import com.android.internal.widget.LockPatternUtils;
95 import com.android.server.LocalServices;
96 
97 import org.xmlpull.v1.XmlPullParserException;
98 
99 import java.io.FileDescriptor;
100 import java.io.IOException;
101 import java.io.PrintWriter;
102 import java.util.ArrayList;
103 import java.util.Arrays;
104 import java.util.Collections;
105 import java.util.HashMap;
106 import java.util.HashSet;
107 import java.util.Iterator;
108 import java.util.List;
109 import java.util.Map;
110 import java.util.Set;
111 import java.util.concurrent.CopyOnWriteArrayList;
112 
113 /**
114  * This class is instantiated by the system as a system level service and can be
115  * accessed only by the system. The task of this service is to be a centralized
116  * event dispatch for {@link AccessibilityEvent}s generated across all processes
117  * on the device. Events are dispatched to {@link AccessibilityService}s.
118  */
119 public class AccessibilityManagerService extends IAccessibilityManager.Stub {
120 
121     private static final boolean DEBUG = false;
122 
123     private static final String LOG_TAG = "AccessibilityManagerService";
124 
125     // TODO: This is arbitrary. When there is time implement this by watching
126     //       when that accessibility services are bound.
127     private static final int WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS = 3000;
128 
129     private static final int WAIT_WINDOWS_TIMEOUT_MILLIS = 5000;
130 
131     private static final String FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE =
132         "registerUiTestAutomationService";
133 
134     private static final String TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED =
135             "temporaryEnableAccessibilityStateUntilKeyguardRemoved";
136 
137     private static final String GET_WINDOW_TOKEN = "getWindowToken";
138 
139     private static final ComponentName sFakeAccessibilityServiceComponentName =
140             new ComponentName("foo.bar", "FakeService");
141 
142     private static final String FUNCTION_DUMP = "dump";
143 
144     private static final char COMPONENT_NAME_SEPARATOR = ':';
145 
146     private static final int OWN_PROCESS_ID = android.os.Process.myPid();
147 
148     private static final int MAX_POOL_SIZE = 10;
149 
150     private static final int WINDOW_ID_UNKNOWN = -1;
151 
152     private static int sIdCounter = 0;
153 
154     private static int sNextWindowId;
155 
156     private final Context mContext;
157 
158     private final Object mLock = new Object();
159 
160     private final Pool<PendingEvent> mPendingEventPool =
161             new SimplePool<>(MAX_POOL_SIZE);
162 
163     private final SimpleStringSplitter mStringColonSplitter =
164             new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
165 
166     private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList =
167             new ArrayList<>();
168 
169     private final Rect mTempRect = new Rect();
170 
171     private final Rect mTempRect1 = new Rect();
172 
173     private final Point mTempPoint = new Point();
174 
175     private final PackageManager mPackageManager;
176 
177     private final WindowManagerInternal mWindowManagerService;
178 
179     private final SecurityPolicy mSecurityPolicy;
180 
181     private final MainHandler mMainHandler;
182 
183     private InteractionBridge mInteractionBridge;
184 
185     private AlertDialog mEnableTouchExplorationDialog;
186 
187     private AccessibilityInputFilter mInputFilter;
188 
189     private boolean mHasInputFilter;
190 
191     private final Set<ComponentName> mTempComponentNameSet = new HashSet<>();
192 
193     private final List<AccessibilityServiceInfo> mTempAccessibilityServiceInfoList =
194             new ArrayList<>();
195 
196     private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients =
197             new RemoteCallbackList<>();
198 
199     private final SparseArray<AccessibilityConnectionWrapper> mGlobalInteractionConnections =
200             new SparseArray<>();
201 
202     private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<>();
203 
204     private final SparseArray<UserState> mUserStates = new SparseArray<>();
205 
206     private final UserManager mUserManager;
207 
208     private final LockPatternUtils mLockPatternUtils;
209 
210     private int mCurrentUserId = UserHandle.USER_OWNER;
211 
212     //TODO: Remove this hack
213     private boolean mInitialized;
214 
215     private WindowsForAccessibilityCallback mWindowsForAccessibilityCallback;
216 
getCurrentUserStateLocked()217     private UserState getCurrentUserStateLocked() {
218         return getUserStateLocked(mCurrentUserId);
219     }
220 
221     /**
222      * Creates a new instance.
223      *
224      * @param context A {@link Context} instance.
225      */
AccessibilityManagerService(Context context)226     public AccessibilityManagerService(Context context) {
227         mContext = context;
228         mPackageManager = mContext.getPackageManager();
229         mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
230         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
231         mSecurityPolicy = new SecurityPolicy();
232         mMainHandler = new MainHandler(mContext.getMainLooper());
233         mLockPatternUtils = new LockPatternUtils(context);
234         registerBroadcastReceivers();
235         new AccessibilityContentObserver(mMainHandler).register(
236                 context.getContentResolver());
237     }
238 
getUserStateLocked(int userId)239     private UserState getUserStateLocked(int userId) {
240         UserState state = mUserStates.get(userId);
241         if (state == null) {
242             state = new UserState(userId);
243             mUserStates.put(userId, state);
244         }
245         return state;
246     }
247 
registerBroadcastReceivers()248     private void registerBroadcastReceivers() {
249         PackageMonitor monitor = new PackageMonitor() {
250             @Override
251             public void onSomePackagesChanged() {
252                 synchronized (mLock) {
253                     // Only the profile parent can install accessibility services.
254                     // Therefore we ignore packages from linked profiles.
255                     if (getChangingUserId() != mCurrentUserId) {
256                         return;
257                     }
258                     // We will update when the automation service dies.
259                     UserState userState = getCurrentUserStateLocked();
260                     // We have to reload the installed services since some services may
261                     // have different attributes, resolve info (does not support equals),
262                     // etc. Remove them then to force reload. Do it even if automation is
263                     // running since when it goes away, we will have to reload as well.
264                     userState.mInstalledServices.clear();
265                     if (userState.mUiAutomationService == null) {
266                         if (readConfigurationForUserStateLocked(userState)) {
267                             onUserStateChangedLocked(userState);
268                         }
269                     }
270                 }
271             }
272 
273             @Override
274             public void onPackageRemoved(String packageName, int uid) {
275                 synchronized (mLock) {
276                     final int userId = getChangingUserId();
277                     // Only the profile parent can install accessibility services.
278                     // Therefore we ignore packages from linked profiles.
279                     if (userId != mCurrentUserId) {
280                         return;
281                     }
282                     UserState userState = getUserStateLocked(userId);
283                     Iterator<ComponentName> it = userState.mEnabledServices.iterator();
284                     while (it.hasNext()) {
285                         ComponentName comp = it.next();
286                         String compPkg = comp.getPackageName();
287                         if (compPkg.equals(packageName)) {
288                             it.remove();
289                             // Update the enabled services setting.
290                             persistComponentNamesToSettingLocked(
291                                     Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
292                                     userState.mEnabledServices, userId);
293                             // Update the touch exploration granted services setting.
294                             userState.mTouchExplorationGrantedServices.remove(comp);
295                             persistComponentNamesToSettingLocked(
296                                     Settings.Secure.
297                                     TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
298                                     userState.mTouchExplorationGrantedServices, userId);
299                             // We will update when the automation service dies.
300                             if (userState.mUiAutomationService == null) {
301                                 onUserStateChangedLocked(userState);
302                             }
303                             return;
304                         }
305                     }
306                 }
307             }
308 
309             @Override
310             public boolean onHandleForceStop(Intent intent, String[] packages,
311                     int uid, boolean doit) {
312                 synchronized (mLock) {
313                     final int userId = getChangingUserId();
314                     // Only the profile parent can install accessibility services.
315                     // Therefore we ignore packages from linked profiles.
316                     if (userId != mCurrentUserId) {
317                         return false;
318                     }
319                     UserState userState = getUserStateLocked(userId);
320                     Iterator<ComponentName> it = userState.mEnabledServices.iterator();
321                     while (it.hasNext()) {
322                         ComponentName comp = it.next();
323                         String compPkg = comp.getPackageName();
324                         for (String pkg : packages) {
325                             if (compPkg.equals(pkg)) {
326                                 if (!doit) {
327                                     return true;
328                                 }
329                                 it.remove();
330                                 persistComponentNamesToSettingLocked(
331                                         Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
332                                         userState.mEnabledServices, userId);
333                                 // We will update when the automation service dies.
334                                 if (userState.mUiAutomationService == null) {
335                                     onUserStateChangedLocked(userState);
336                                 }
337                             }
338                         }
339                     }
340                     return false;
341                 }
342             }
343         };
344 
345         // package changes
346         monitor.register(mContext, null,  UserHandle.ALL, true);
347 
348         // user change and unlock
349         IntentFilter intentFilter = new IntentFilter();
350         intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
351         intentFilter.addAction(Intent.ACTION_USER_REMOVED);
352         intentFilter.addAction(Intent.ACTION_USER_PRESENT);
353         intentFilter.addAction(Intent.ACTION_SETTING_RESTORED);
354 
355         mContext.registerReceiverAsUser(new BroadcastReceiver() {
356             @Override
357             public void onReceive(Context context, Intent intent) {
358                 String action = intent.getAction();
359                 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
360                     switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
361                 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
362                     removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
363                 } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
364                     // We will update when the automation service dies.
365                     UserState userState = getCurrentUserStateLocked();
366                     if (userState.mUiAutomationService == null) {
367                         if (readConfigurationForUserStateLocked(userState)) {
368                             onUserStateChangedLocked(userState);
369                         }
370                     }
371                 } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) {
372                     final String which = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
373                     if (Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES.equals(which)) {
374                         synchronized (mLock) {
375                             restoreEnabledAccessibilityServicesLocked(
376                                     intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE),
377                                     intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE));
378                         }
379                     }
380                 }
381             }
382         }, UserHandle.ALL, intentFilter, null, null);
383     }
384 
385     @Override
addClient(IAccessibilityManagerClient client, int userId)386     public int addClient(IAccessibilityManagerClient client, int userId) {
387         synchronized (mLock) {
388             // We treat calls from a profile as if made by its parent as profiles
389             // share the accessibility state of the parent. The call below
390             // performs the current profile parent resolution.
391             final int resolvedUserId = mSecurityPolicy
392                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
393             // If the client is from a process that runs across users such as
394             // the system UI or the system we add it to the global state that
395             // is shared across users.
396             UserState userState = getUserStateLocked(resolvedUserId);
397             if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
398                 mGlobalClients.register(client);
399                 if (DEBUG) {
400                     Slog.i(LOG_TAG, "Added global client for pid:" + Binder.getCallingPid());
401                 }
402                 return userState.getClientState();
403             } else {
404                 userState.mClients.register(client);
405                 // If this client is not for the current user we do not
406                 // return a state since it is not for the foreground user.
407                 // We will send the state to the client on a user switch.
408                 if (DEBUG) {
409                     Slog.i(LOG_TAG, "Added user client for pid:" + Binder.getCallingPid()
410                             + " and userId:" + mCurrentUserId);
411                 }
412                 return (resolvedUserId == mCurrentUserId) ? userState.getClientState() : 0;
413             }
414         }
415     }
416 
417     @Override
sendAccessibilityEvent(AccessibilityEvent event, int userId)418     public boolean sendAccessibilityEvent(AccessibilityEvent event, int userId) {
419         synchronized (mLock) {
420             // We treat calls from a profile as if made by its parent as profiles
421             // share the accessibility state of the parent. The call below
422             // performs the current profile parent resolution..
423             final int resolvedUserId = mSecurityPolicy
424                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
425             // This method does nothing for a background user.
426             if (resolvedUserId != mCurrentUserId) {
427                 return true; // yes, recycle the event
428             }
429             if (mSecurityPolicy.canDispatchAccessibilityEventLocked(event)) {
430                 mSecurityPolicy.updateActiveAndAccessibilityFocusedWindowLocked(event.getWindowId(),
431                         event.getSourceNodeId(), event.getEventType());
432                 mSecurityPolicy.updateEventSourceLocked(event);
433                 notifyAccessibilityServicesDelayedLocked(event, false);
434                 notifyAccessibilityServicesDelayedLocked(event, true);
435             }
436             if (mHasInputFilter && mInputFilter != null) {
437                 mMainHandler.obtainMessage(MainHandler.MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER,
438                         AccessibilityEvent.obtain(event)).sendToTarget();
439             }
440             event.recycle();
441             getUserStateLocked(resolvedUserId).mHandledFeedbackTypes = 0;
442         }
443         return (OWN_PROCESS_ID != Binder.getCallingPid());
444     }
445 
446     @Override
getInstalledAccessibilityServiceList(int userId)447     public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
448         synchronized (mLock) {
449             // We treat calls from a profile as if made by its parent as profiles
450             // share the accessibility state of the parent. The call below
451             // performs the current profile parent resolution.
452             final int resolvedUserId = mSecurityPolicy
453                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
454             // The automation service is a fake one and should not be reported
455             // to clients as being installed - it really is not.
456             UserState userState = getUserStateLocked(resolvedUserId);
457             if (userState.mUiAutomationService != null) {
458                 List<AccessibilityServiceInfo> installedServices = new ArrayList<>();
459                 installedServices.addAll(userState.mInstalledServices);
460                 installedServices.remove(userState.mUiAutomationService.mAccessibilityServiceInfo);
461                 return installedServices;
462             }
463             return userState.mInstalledServices;
464         }
465     }
466 
467     @Override
getEnabledAccessibilityServiceList(int feedbackType, int userId)468     public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType,
469             int userId) {
470         List<AccessibilityServiceInfo> result = null;
471         synchronized (mLock) {
472             // We treat calls from a profile as if made by its parent as profiles
473             // share the accessibility state of the parent. The call below
474             // performs the current profile parent resolution.
475             final int resolvedUserId = mSecurityPolicy
476                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
477 
478             // The automation service is a fake one and should not be reported
479             // to clients as being enabled. The automation service is always the
480             // only active one, if it exists.
481             UserState userState = getUserStateLocked(resolvedUserId);
482             if (userState.mUiAutomationService != null) {
483                 return Collections.emptyList();
484             }
485 
486             result = mEnabledServicesForFeedbackTempList;
487             result.clear();
488             List<Service> services = userState.mBoundServices;
489             while (feedbackType != 0) {
490                 final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackType));
491                 feedbackType &= ~feedbackTypeBit;
492                 final int serviceCount = services.size();
493                 for (int i = 0; i < serviceCount; i++) {
494                     Service service = services.get(i);
495                     if ((service.mFeedbackType & feedbackTypeBit) != 0) {
496                         result.add(service.mAccessibilityServiceInfo);
497                     }
498                 }
499             }
500         }
501         return result;
502     }
503 
504     @Override
interrupt(int userId)505     public void interrupt(int userId) {
506         CopyOnWriteArrayList<Service> services;
507         synchronized (mLock) {
508             // We treat calls from a profile as if made by its parent as profiles
509             // share the accessibility state of the parent. The call below
510             // performs the current profile parent resolution.
511             final int resolvedUserId = mSecurityPolicy
512                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
513             // This method does nothing for a background user.
514             if (resolvedUserId != mCurrentUserId) {
515                 return;
516             }
517             services = getUserStateLocked(resolvedUserId).mBoundServices;
518         }
519         for (int i = 0, count = services.size(); i < count; i++) {
520             Service service = services.get(i);
521             try {
522                 service.mServiceInterface.onInterrupt();
523             } catch (RemoteException re) {
524                 Slog.e(LOG_TAG, "Error during sending interrupt request to "
525                     + service.mService, re);
526             }
527         }
528     }
529 
530     @Override
addAccessibilityInteractionConnection(IWindow windowToken, IAccessibilityInteractionConnection connection, int userId)531     public int addAccessibilityInteractionConnection(IWindow windowToken,
532             IAccessibilityInteractionConnection connection, int userId) throws RemoteException {
533         synchronized (mLock) {
534             // We treat calls from a profile as if made by its parent as profiles
535             // share the accessibility state of the parent. The call below
536             // performs the current profile parent resolution.
537             final int resolvedUserId = mSecurityPolicy
538                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
539             final int windowId = sNextWindowId++;
540             // If the window is from a process that runs across users such as
541             // the system UI or the system we add it to the global state that
542             // is shared across users.
543             if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
544                 AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
545                         windowId, connection, UserHandle.USER_ALL);
546                 wrapper.linkToDeath();
547                 mGlobalInteractionConnections.put(windowId, wrapper);
548                 mGlobalWindowTokens.put(windowId, windowToken.asBinder());
549                 if (DEBUG) {
550                     Slog.i(LOG_TAG, "Added global connection for pid:" + Binder.getCallingPid()
551                             + " with windowId: " + windowId + " and  token: " + windowToken.asBinder());
552                 }
553             } else {
554                 AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
555                         windowId, connection, resolvedUserId);
556                 wrapper.linkToDeath();
557                 UserState userState = getUserStateLocked(resolvedUserId);
558                 userState.mInteractionConnections.put(windowId, wrapper);
559                 userState.mWindowTokens.put(windowId, windowToken.asBinder());
560                 if (DEBUG) {
561                     Slog.i(LOG_TAG, "Added user connection for pid:" + Binder.getCallingPid()
562                             + " with windowId: " + windowId + " and userId:" + mCurrentUserId
563                             + " and  token: " + windowToken.asBinder());
564                 }
565             }
566             return windowId;
567         }
568     }
569 
570     @Override
removeAccessibilityInteractionConnection(IWindow window)571     public void removeAccessibilityInteractionConnection(IWindow window) {
572         synchronized (mLock) {
573             // We treat calls from a profile as if made by its parent as profiles
574             // share the accessibility state of the parent. The call below
575             // performs the current profile parent resolution.
576             mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
577                     UserHandle.getCallingUserId());
578             IBinder token = window.asBinder();
579             final int removedWindowId = removeAccessibilityInteractionConnectionInternalLocked(
580                     token, mGlobalWindowTokens, mGlobalInteractionConnections);
581             if (removedWindowId >= 0) {
582                 if (DEBUG) {
583                     Slog.i(LOG_TAG, "Removed global connection for pid:" + Binder.getCallingPid()
584                             + " with windowId: " + removedWindowId + " and token: " + window.asBinder());
585                 }
586                 return;
587             }
588             final int userCount = mUserStates.size();
589             for (int i = 0; i < userCount; i++) {
590                 UserState userState = mUserStates.valueAt(i);
591                 final int removedWindowIdForUser =
592                         removeAccessibilityInteractionConnectionInternalLocked(
593                         token, userState.mWindowTokens, userState.mInteractionConnections);
594                 if (removedWindowIdForUser >= 0) {
595                     if (DEBUG) {
596                         Slog.i(LOG_TAG, "Removed user connection for pid:" + Binder.getCallingPid()
597                                 + " with windowId: " + removedWindowIdForUser + " and userId:"
598                                 + mUserStates.keyAt(i) + " and token: " + window.asBinder());
599                     }
600                     return;
601                 }
602             }
603         }
604     }
605 
removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken, SparseArray<IBinder> windowTokens, SparseArray<AccessibilityConnectionWrapper> interactionConnections)606     private int removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken,
607             SparseArray<IBinder> windowTokens,
608             SparseArray<AccessibilityConnectionWrapper> interactionConnections) {
609         final int count = windowTokens.size();
610         for (int i = 0; i < count; i++) {
611             if (windowTokens.valueAt(i) == windowToken) {
612                 final int windowId = windowTokens.keyAt(i);
613                 windowTokens.removeAt(i);
614                 AccessibilityConnectionWrapper wrapper = interactionConnections.get(windowId);
615                 wrapper.unlinkToDeath();
616                 interactionConnections.remove(windowId);
617                 return windowId;
618             }
619         }
620         return -1;
621     }
622 
623     @Override
registerUiTestAutomationService(IBinder owner, IAccessibilityServiceClient serviceClient, AccessibilityServiceInfo accessibilityServiceInfo)624     public void registerUiTestAutomationService(IBinder owner,
625             IAccessibilityServiceClient serviceClient,
626             AccessibilityServiceInfo accessibilityServiceInfo) {
627         mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
628                 FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE);
629 
630         accessibilityServiceInfo.setComponentName(sFakeAccessibilityServiceComponentName);
631 
632         synchronized (mLock) {
633             UserState userState = getCurrentUserStateLocked();
634 
635             if (userState.mUiAutomationService != null) {
636                 throw new IllegalStateException("UiAutomationService " + serviceClient
637                         + "already registered!");
638             }
639 
640             try {
641                 owner.linkToDeath(userState.mUiAutomationSerivceOnwerDeathRecipient, 0);
642             } catch (RemoteException re) {
643                 Slog.e(LOG_TAG, "Couldn't register for the death of a"
644                         + " UiTestAutomationService!", re);
645                 return;
646             }
647 
648             userState.mUiAutomationServiceOwner = owner;
649             userState.mUiAutomationServiceClient = serviceClient;
650 
651             // Set the temporary state.
652             userState.mIsAccessibilityEnabled = true;
653             userState.mIsTouchExplorationEnabled = false;
654             userState.mIsEnhancedWebAccessibilityEnabled = false;
655             userState.mIsDisplayMagnificationEnabled = false;
656             userState.mInstalledServices.add(accessibilityServiceInfo);
657             userState.mEnabledServices.clear();
658             userState.mEnabledServices.add(sFakeAccessibilityServiceComponentName);
659             userState.mTouchExplorationGrantedServices.add(sFakeAccessibilityServiceComponentName);
660 
661             // Use the new state instead of settings.
662             onUserStateChangedLocked(userState);
663         }
664     }
665 
666     @Override
unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient)667     public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) {
668         synchronized (mLock) {
669             UserState userState = getCurrentUserStateLocked();
670             // Automation service is not bound, so pretend it died to perform clean up.
671             if (userState.mUiAutomationService != null
672                     && serviceClient != null
673                     && userState.mUiAutomationService.mServiceInterface != null
674                     && userState.mUiAutomationService.mServiceInterface.asBinder()
675                     == serviceClient.asBinder()) {
676                 userState.mUiAutomationService.binderDied();
677             } else {
678                 throw new IllegalStateException("UiAutomationService " + serviceClient
679                         + " not registered!");
680             }
681         }
682     }
683 
684     @Override
temporaryEnableAccessibilityStateUntilKeyguardRemoved( ComponentName service, boolean touchExplorationEnabled)685     public void temporaryEnableAccessibilityStateUntilKeyguardRemoved(
686             ComponentName service, boolean touchExplorationEnabled) {
687         mSecurityPolicy.enforceCallingPermission(
688                 Manifest.permission.TEMPORARY_ENABLE_ACCESSIBILITY,
689                 TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED);
690         if (!mWindowManagerService.isKeyguardLocked()) {
691             return;
692         }
693         synchronized (mLock) {
694             // Set the temporary state.
695             UserState userState = getCurrentUserStateLocked();
696 
697             // This is a nop if UI automation is enabled.
698             if (userState.mUiAutomationService != null) {
699                 return;
700             }
701 
702             userState.mIsAccessibilityEnabled = true;
703             userState.mIsTouchExplorationEnabled = touchExplorationEnabled;
704             userState.mIsEnhancedWebAccessibilityEnabled = false;
705             userState.mIsDisplayMagnificationEnabled = false;
706             userState.mEnabledServices.clear();
707             userState.mEnabledServices.add(service);
708             userState.mBindingServices.clear();
709             userState.mTouchExplorationGrantedServices.clear();
710             userState.mTouchExplorationGrantedServices.add(service);
711 
712             // User the current state instead settings.
713             onUserStateChangedLocked(userState);
714         }
715     }
716 
717     @Override
getWindowToken(int windowId)718     public IBinder getWindowToken(int windowId) {
719         mSecurityPolicy.enforceCallingPermission(
720                 Manifest.permission.RETRIEVE_WINDOW_TOKEN,
721                 GET_WINDOW_TOKEN);
722         synchronized (mLock) {
723             // We treat calls from a profile as if made by its parent as profiles
724             // share the accessibility state of the parent. The call below
725             // performs the current profile parent resolution.
726             final int resolvedUserId = mSecurityPolicy
727                     .resolveCallingUserIdEnforcingPermissionsLocked(
728                             UserHandle.getCallingUserId());
729             if (resolvedUserId != mCurrentUserId) {
730                 return null;
731             }
732             if (mSecurityPolicy.findWindowById(windowId) == null) {
733                 return null;
734             }
735             IBinder token = mGlobalWindowTokens.get(windowId);
736             if (token != null) {
737                 return token;
738             }
739             return getCurrentUserStateLocked().mWindowTokens.get(windowId);
740         }
741     }
742 
onGesture(int gestureId)743     boolean onGesture(int gestureId) {
744         synchronized (mLock) {
745             boolean handled = notifyGestureLocked(gestureId, false);
746             if (!handled) {
747                 handled = notifyGestureLocked(gestureId, true);
748             }
749             return handled;
750         }
751     }
752 
notifyKeyEvent(KeyEvent event, int policyFlags)753     boolean notifyKeyEvent(KeyEvent event, int policyFlags) {
754         synchronized (mLock) {
755             KeyEvent localClone = KeyEvent.obtain(event);
756             boolean handled = notifyKeyEventLocked(localClone, policyFlags, false);
757             if (!handled) {
758                 handled = notifyKeyEventLocked(localClone, policyFlags, true);
759             }
760             return handled;
761         }
762     }
763 
764     /**
765      * Gets a point within the accessibility focused node where we can send down
766      * and up events to perform a click.
767      *
768      * @param outPoint The click point to populate.
769      * @return Whether accessibility a click point was found and set.
770      */
771     // TODO: (multi-display) Make sure this works for multiple displays.
getAccessibilityFocusClickPointInScreen(Point outPoint)772     boolean getAccessibilityFocusClickPointInScreen(Point outPoint) {
773         return getInteractionBridgeLocked()
774                 .getAccessibilityFocusClickPointInScreenNotLocked(outPoint);
775     }
776 
777     /**
778      * Gets the bounds of a window.
779      *
780      * @param outBounds The output to which to write the bounds.
781      */
getWindowBounds(int windowId, Rect outBounds)782     boolean getWindowBounds(int windowId, Rect outBounds) {
783         IBinder token;
784         synchronized (mLock) {
785             token = mGlobalWindowTokens.get(windowId);
786             if (token == null) {
787                 token = getCurrentUserStateLocked().mWindowTokens.get(windowId);
788             }
789         }
790         mWindowManagerService.getWindowFrame(token, outBounds);
791         if (!outBounds.isEmpty()) {
792             return true;
793         }
794         return false;
795     }
796 
accessibilityFocusOnlyInActiveWindow()797     boolean accessibilityFocusOnlyInActiveWindow() {
798         synchronized (mLock) {
799             return mWindowsForAccessibilityCallback == null;
800         }
801     }
802 
getActiveWindowId()803     int getActiveWindowId() {
804         return mSecurityPolicy.getActiveWindowId();
805     }
806 
onTouchInteractionStart()807     void onTouchInteractionStart() {
808         mSecurityPolicy.onTouchInteractionStart();
809     }
810 
onTouchInteractionEnd()811     void onTouchInteractionEnd() {
812         mSecurityPolicy.onTouchInteractionEnd();
813     }
814 
onMagnificationStateChanged()815     void onMagnificationStateChanged() {
816         notifyClearAccessibilityCacheLocked();
817     }
818 
switchUser(int userId)819     private void switchUser(int userId) {
820         synchronized (mLock) {
821             if (mCurrentUserId == userId && mInitialized) {
822                 return;
823             }
824 
825             // Disconnect from services for the old user.
826             UserState oldUserState = getCurrentUserStateLocked();
827             oldUserState.onSwitchToAnotherUser();
828 
829             // Disable the local managers for the old user.
830             if (oldUserState.mClients.getRegisteredCallbackCount() > 0) {
831                 mMainHandler.obtainMessage(MainHandler.MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER,
832                         oldUserState.mUserId, 0).sendToTarget();
833             }
834 
835             // Announce user changes only if more that one exist.
836             UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
837             final boolean announceNewUser = userManager.getUsers().size() > 1;
838 
839             // The user changed.
840             mCurrentUserId = userId;
841 
842             UserState userState = getCurrentUserStateLocked();
843             if (userState.mUiAutomationService != null) {
844                 // Switching users disables the UI automation service.
845                 userState.mUiAutomationService.binderDied();
846             }
847 
848             readConfigurationForUserStateLocked(userState);
849             // Even if reading did not yield change, we have to update
850             // the state since the context in which the current user
851             // state was used has changed since it was inactive.
852             onUserStateChangedLocked(userState);
853 
854             if (announceNewUser) {
855                 // Schedule announcement of the current user if needed.
856                 mMainHandler.sendEmptyMessageDelayed(MainHandler.MSG_ANNOUNCE_NEW_USER_IF_NEEDED,
857                         WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS);
858             }
859         }
860     }
861 
removeUser(int userId)862     private void removeUser(int userId) {
863         synchronized (mLock) {
864             mUserStates.remove(userId);
865         }
866     }
867 
868     // Called only during settings restore; currently supports only the owner user
restoreEnabledAccessibilityServicesLocked(String oldSetting, String newSetting)869     void restoreEnabledAccessibilityServicesLocked(String oldSetting, String newSetting) {
870         readComponentNamesFromStringLocked(oldSetting, mTempComponentNameSet, false);
871         readComponentNamesFromStringLocked(newSetting, mTempComponentNameSet, true);
872 
873         UserState userState = getUserStateLocked(UserHandle.USER_OWNER);
874         userState.mEnabledServices.clear();
875         userState.mEnabledServices.addAll(mTempComponentNameSet);
876         persistComponentNamesToSettingLocked(
877                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
878                 userState.mEnabledServices,
879                 UserHandle.USER_OWNER);
880         onUserStateChangedLocked(userState);
881     }
882 
getInteractionBridgeLocked()883     private InteractionBridge getInteractionBridgeLocked() {
884         if (mInteractionBridge == null) {
885             mInteractionBridge = new InteractionBridge();
886         }
887         return mInteractionBridge;
888     }
889 
notifyGestureLocked(int gestureId, boolean isDefault)890     private boolean notifyGestureLocked(int gestureId, boolean isDefault) {
891         // TODO: Now we are giving the gestures to the last enabled
892         //       service that can handle them which is the last one
893         //       in our list since we write the last enabled as the
894         //       last record in the enabled services setting. Ideally,
895         //       the user should make the call which service handles
896         //       gestures. However, only one service should handle
897         //       gestures to avoid user frustration when different
898         //       behavior is observed from different combinations of
899         //       enabled accessibility services.
900         UserState state = getCurrentUserStateLocked();
901         for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
902             Service service = state.mBoundServices.get(i);
903             if (service.mRequestTouchExplorationMode && service.mIsDefault == isDefault) {
904                 service.notifyGesture(gestureId);
905                 return true;
906             }
907         }
908         return false;
909     }
910 
notifyKeyEventLocked(KeyEvent event, int policyFlags, boolean isDefault)911     private boolean notifyKeyEventLocked(KeyEvent event, int policyFlags, boolean isDefault) {
912         // TODO: Now we are giving the key events to the last enabled
913         //       service that can handle them Ideally, the user should
914         //       make the call which service handles key events. However,
915         //       only one service should handle key events to avoid user
916         //       frustration when different behavior is observed from
917         //       different combinations of enabled accessibility services.
918         UserState state = getCurrentUserStateLocked();
919         for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
920             Service service = state.mBoundServices.get(i);
921             // Key events are handled only by services that declared
922             // this capability and requested to filter key events.
923             if (!service.mRequestFilterKeyEvents ||
924                     (service.mAccessibilityServiceInfo.getCapabilities() & AccessibilityServiceInfo
925                             .CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) == 0) {
926                 continue;
927             }
928             if (service.mIsDefault == isDefault) {
929                 service.notifyKeyEvent(event, policyFlags);
930                 return true;
931             }
932         }
933         return false;
934     }
935 
notifyClearAccessibilityCacheLocked()936     private void notifyClearAccessibilityCacheLocked() {
937         UserState state = getCurrentUserStateLocked();
938         for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
939             Service service = state.mBoundServices.get(i);
940             service.notifyClearAccessibilityNodeInfoCache();
941         }
942     }
943 
944     /**
945      * Removes an AccessibilityInteractionConnection.
946      *
947      * @param windowId The id of the window to which the connection is targeted.
948      * @param userId The id of the user owning the connection. UserHandle.USER_ALL
949      *     if global.
950      */
removeAccessibilityInteractionConnectionLocked(int windowId, int userId)951     private void removeAccessibilityInteractionConnectionLocked(int windowId, int userId) {
952         if (userId == UserHandle.USER_ALL) {
953             mGlobalWindowTokens.remove(windowId);
954             mGlobalInteractionConnections.remove(windowId);
955         } else {
956             UserState userState = getCurrentUserStateLocked();
957             userState.mWindowTokens.remove(windowId);
958             userState.mInteractionConnections.remove(windowId);
959         }
960         if (DEBUG) {
961             Slog.i(LOG_TAG, "Removing interaction connection to windowId: " + windowId);
962         }
963     }
964 
readInstalledAccessibilityServiceLocked(UserState userState)965     private boolean readInstalledAccessibilityServiceLocked(UserState userState) {
966         mTempAccessibilityServiceInfoList.clear();
967 
968         List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser(
969                 new Intent(AccessibilityService.SERVICE_INTERFACE),
970                 PackageManager.GET_SERVICES
971                   | PackageManager.GET_META_DATA
972                   | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
973                 mCurrentUserId);
974 
975         for (int i = 0, count = installedServices.size(); i < count; i++) {
976             ResolveInfo resolveInfo = installedServices.get(i);
977             ServiceInfo serviceInfo = resolveInfo.serviceInfo;
978             if (!android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE.equals(
979                     serviceInfo.permission)) {
980                 Slog.w(LOG_TAG, "Skipping accessibilty service " + new ComponentName(
981                         serviceInfo.packageName, serviceInfo.name).flattenToShortString()
982                         + ": it does not require the permission "
983                         + android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE);
984                 continue;
985             }
986             AccessibilityServiceInfo accessibilityServiceInfo;
987             try {
988                 accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext);
989                 mTempAccessibilityServiceInfoList.add(accessibilityServiceInfo);
990             } catch (XmlPullParserException | IOException xppe) {
991                 Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe);
992             }
993         }
994 
995         if (!mTempAccessibilityServiceInfoList.equals(userState.mInstalledServices)) {
996             userState.mInstalledServices.clear();
997             userState.mInstalledServices.addAll(mTempAccessibilityServiceInfoList);
998             mTempAccessibilityServiceInfoList.clear();
999             return true;
1000         }
1001 
1002         mTempAccessibilityServiceInfoList.clear();
1003         return false;
1004     }
1005 
readEnabledAccessibilityServicesLocked(UserState userState)1006     private boolean readEnabledAccessibilityServicesLocked(UserState userState) {
1007         mTempComponentNameSet.clear();
1008         readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
1009                 userState.mUserId, mTempComponentNameSet);
1010         if (!mTempComponentNameSet.equals(userState.mEnabledServices)) {
1011             userState.mEnabledServices.clear();
1012             userState.mEnabledServices.addAll(mTempComponentNameSet);
1013             mTempComponentNameSet.clear();
1014             return true;
1015         }
1016         mTempComponentNameSet.clear();
1017         return false;
1018     }
1019 
readTouchExplorationGrantedAccessibilityServicesLocked( UserState userState)1020     private boolean readTouchExplorationGrantedAccessibilityServicesLocked(
1021             UserState userState) {
1022         mTempComponentNameSet.clear();
1023         readComponentNamesFromSettingLocked(
1024                 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
1025                 userState.mUserId, mTempComponentNameSet);
1026         if (!mTempComponentNameSet.equals(userState.mTouchExplorationGrantedServices)) {
1027             userState.mTouchExplorationGrantedServices.clear();
1028             userState.mTouchExplorationGrantedServices.addAll(mTempComponentNameSet);
1029             mTempComponentNameSet.clear();
1030             return true;
1031         }
1032         mTempComponentNameSet.clear();
1033         return false;
1034     }
1035 
1036     /**
1037      * Performs {@link AccessibilityService}s delayed notification. The delay is configurable
1038      * and denotes the period after the last event before notifying the service.
1039      *
1040      * @param event The event.
1041      * @param isDefault True to notify default listeners, not default services.
1042      */
notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event, boolean isDefault)1043     private void notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event,
1044             boolean isDefault) {
1045         try {
1046             UserState state = getCurrentUserStateLocked();
1047             for (int i = 0, count = state.mBoundServices.size(); i < count; i++) {
1048                 Service service = state.mBoundServices.get(i);
1049 
1050                 if (service.mIsDefault == isDefault) {
1051                     if (canDispatchEventToServiceLocked(service, event,
1052                             state.mHandledFeedbackTypes)) {
1053                         state.mHandledFeedbackTypes |= service.mFeedbackType;
1054                         service.notifyAccessibilityEvent(event);
1055                     }
1056                 }
1057             }
1058         } catch (IndexOutOfBoundsException oobe) {
1059             // An out of bounds exception can happen if services are going away
1060             // as the for loop is running. If that happens, just bail because
1061             // there are no more services to notify.
1062         }
1063     }
1064 
addServiceLocked(Service service, UserState userState)1065     private void addServiceLocked(Service service, UserState userState) {
1066         try {
1067             service.onAdded();
1068             userState.mBoundServices.add(service);
1069             userState.mComponentNameToServiceMap.put(service.mComponentName, service);
1070         } catch (RemoteException re) {
1071             /* do nothing */
1072         }
1073     }
1074 
1075     /**
1076      * Removes a service.
1077      *
1078      * @param service The service.
1079      */
removeServiceLocked(Service service, UserState userState)1080     private void removeServiceLocked(Service service, UserState userState) {
1081         userState.mBoundServices.remove(service);
1082         userState.mComponentNameToServiceMap.remove(service.mComponentName);
1083         service.onRemoved();
1084     }
1085 
1086     /**
1087      * Determines if given event can be dispatched to a service based on the package of the
1088      * event source and already notified services for that event type. Specifically, a
1089      * service is notified if it is interested in events from the package and no other service
1090      * providing the same feedback type has been notified. Exception are services the
1091      * provide generic feedback (feedback type left as a safety net for unforeseen feedback
1092      * types) which are always notified.
1093      *
1094      * @param service The potential receiver.
1095      * @param event The event.
1096      * @param handledFeedbackTypes The feedback types for which services have been notified.
1097      * @return True if the listener should be notified, false otherwise.
1098      */
canDispatchEventToServiceLocked(Service service, AccessibilityEvent event, int handledFeedbackTypes)1099     private boolean canDispatchEventToServiceLocked(Service service, AccessibilityEvent event,
1100             int handledFeedbackTypes) {
1101 
1102         if (!service.canReceiveEventsLocked()) {
1103             return false;
1104         }
1105 
1106         if (event.getWindowId() != WINDOW_ID_UNKNOWN && !event.isImportantForAccessibility()
1107                 && (service.mFetchFlags
1108                         & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) {
1109             return false;
1110         }
1111 
1112         int eventType = event.getEventType();
1113         if ((service.mEventTypes & eventType) != eventType) {
1114             return false;
1115         }
1116 
1117         Set<String> packageNames = service.mPackageNames;
1118         String packageName = (event.getPackageName() != null)
1119                 ? event.getPackageName().toString() : null;
1120 
1121         if (packageNames.isEmpty() || packageNames.contains(packageName)) {
1122             int feedbackType = service.mFeedbackType;
1123             if ((handledFeedbackTypes & feedbackType) != feedbackType
1124                     || feedbackType == AccessibilityServiceInfo.FEEDBACK_GENERIC) {
1125                 return true;
1126             }
1127         }
1128 
1129         return false;
1130     }
1131 
unbindAllServicesLocked(UserState userState)1132     private void unbindAllServicesLocked(UserState userState) {
1133         List<Service> services = userState.mBoundServices;
1134         for (int i = 0, count = services.size(); i < count; i++) {
1135             Service service = services.get(i);
1136             if (service.unbindLocked()) {
1137                 i--;
1138                 count--;
1139             }
1140         }
1141     }
1142 
1143     /**
1144      * Populates a set with the {@link ComponentName}s stored in a colon
1145      * separated value setting for a given user.
1146      *
1147      * @param settingName The setting to parse.
1148      * @param userId The user id.
1149      * @param outComponentNames The output component names.
1150      */
readComponentNamesFromSettingLocked(String settingName, int userId, Set<ComponentName> outComponentNames)1151     private void readComponentNamesFromSettingLocked(String settingName, int userId,
1152             Set<ComponentName> outComponentNames) {
1153         String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
1154                 settingName, userId);
1155         readComponentNamesFromStringLocked(settingValue, outComponentNames, false);
1156     }
1157 
1158     /**
1159      * Populates a set with the {@link ComponentName}s contained in a colon-delimited string.
1160      *
1161      * @param names The colon-delimited string to parse.
1162      * @param outComponentNames The set of component names to be populated based on
1163      *    the contents of the <code>names</code> string.
1164      * @param doMerge If true, the parsed component names will be merged into the output
1165      *    set, rather than replacing the set's existing contents entirely.
1166      */
readComponentNamesFromStringLocked(String names, Set<ComponentName> outComponentNames, boolean doMerge)1167     private void readComponentNamesFromStringLocked(String names,
1168             Set<ComponentName> outComponentNames,
1169             boolean doMerge) {
1170         if (!doMerge) {
1171             outComponentNames.clear();
1172         }
1173         if (names != null) {
1174             TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
1175             splitter.setString(names);
1176             while (splitter.hasNext()) {
1177                 String str = splitter.next();
1178                 if (str == null || str.length() <= 0) {
1179                     continue;
1180                 }
1181                 ComponentName enabledService = ComponentName.unflattenFromString(str);
1182                 if (enabledService != null) {
1183                     outComponentNames.add(enabledService);
1184                 }
1185             }
1186         }
1187     }
1188 
1189     /**
1190      * Persists the component names in the specified setting in a
1191      * colon separated fashion.
1192      *
1193      * @param settingName The setting name.
1194      * @param componentNames The component names.
1195      */
persistComponentNamesToSettingLocked(String settingName, Set<ComponentName> componentNames, int userId)1196     private void persistComponentNamesToSettingLocked(String settingName,
1197             Set<ComponentName> componentNames, int userId) {
1198         StringBuilder builder = new StringBuilder();
1199         for (ComponentName componentName : componentNames) {
1200             if (builder.length() > 0) {
1201                 builder.append(COMPONENT_NAME_SEPARATOR);
1202             }
1203             builder.append(componentName.flattenToShortString());
1204         }
1205         Settings.Secure.putStringForUser(mContext.getContentResolver(),
1206                 settingName, builder.toString(), userId);
1207     }
1208 
manageServicesLocked(UserState userState)1209     private void manageServicesLocked(UserState userState) {
1210         Map<ComponentName, Service> componentNameToServiceMap =
1211                 userState.mComponentNameToServiceMap;
1212         boolean isEnabled = userState.mIsAccessibilityEnabled;
1213 
1214         for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
1215             AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i);
1216             ComponentName componentName = ComponentName.unflattenFromString(
1217                     installedService.getId());
1218             Service service = componentNameToServiceMap.get(componentName);
1219 
1220             if (isEnabled) {
1221                 // Wait for the binding if it is in process.
1222                 if (userState.mBindingServices.contains(componentName)) {
1223                     continue;
1224                 }
1225                 if (userState.mEnabledServices.contains(componentName)) {
1226                     if (service == null) {
1227                         service = new Service(userState.mUserId, componentName, installedService);
1228                     } else if (userState.mBoundServices.contains(service)) {
1229                         continue;
1230                     }
1231                     service.bindLocked();
1232                 } else {
1233                     if (service != null) {
1234                         service.unbindLocked();
1235                     }
1236                 }
1237             } else {
1238                 if (service != null) {
1239                     service.unbindLocked();
1240                 } else {
1241                     userState.mBindingServices.remove(componentName);
1242                 }
1243             }
1244         }
1245 
1246         // No enabled installed services => disable accessibility to avoid
1247         // sending accessibility events with no recipient across processes.
1248         if (isEnabled && userState.mBoundServices.isEmpty()
1249                 && userState.mBindingServices.isEmpty()) {
1250             userState.mIsAccessibilityEnabled = false;
1251             Settings.Secure.putIntForUser(mContext.getContentResolver(),
1252                     Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId);
1253         }
1254     }
1255 
scheduleUpdateClientsIfNeededLocked(UserState userState)1256     private void scheduleUpdateClientsIfNeededLocked(UserState userState) {
1257         final int clientState = userState.getClientState();
1258         if (userState.mLastSentClientState != clientState
1259                 && (mGlobalClients.getRegisteredCallbackCount() > 0
1260                         || userState.mClients.getRegisteredCallbackCount() > 0)) {
1261             userState.mLastSentClientState = clientState;
1262             mMainHandler.obtainMessage(MainHandler.MSG_SEND_STATE_TO_CLIENTS,
1263                     clientState, userState.mUserId) .sendToTarget();
1264         }
1265     }
1266 
scheduleUpdateInputFilter(UserState userState)1267     private void scheduleUpdateInputFilter(UserState userState) {
1268         mMainHandler.obtainMessage(MainHandler.MSG_UPDATE_INPUT_FILTER, userState).sendToTarget();
1269     }
1270 
updateInputFilter(UserState userState)1271     private void updateInputFilter(UserState userState) {
1272         boolean setInputFilter = false;
1273         AccessibilityInputFilter inputFilter = null;
1274         synchronized (mLock) {
1275             int flags = 0;
1276             if (userState.mIsDisplayMagnificationEnabled) {
1277                 flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
1278             }
1279             // Touch exploration without accessibility makes no sense.
1280             if (userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) {
1281                 flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
1282             }
1283             if (userState.mIsFilterKeyEventsEnabled) {
1284                 flags |= AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS;
1285             }
1286             if (flags != 0) {
1287                 if (!mHasInputFilter) {
1288                     mHasInputFilter = true;
1289                     if (mInputFilter == null) {
1290                         mInputFilter = new AccessibilityInputFilter(mContext,
1291                                 AccessibilityManagerService.this);
1292                     }
1293                     inputFilter = mInputFilter;
1294                     setInputFilter = true;
1295                 }
1296                 mInputFilter.setEnabledFeatures(flags);
1297             } else {
1298                 if (mHasInputFilter) {
1299                     mHasInputFilter = false;
1300                     mInputFilter.disableFeatures();
1301                     inputFilter = null;
1302                     setInputFilter = true;
1303                 }
1304             }
1305         }
1306         if (setInputFilter) {
1307             mWindowManagerService.setInputFilter(inputFilter);
1308         }
1309     }
1310 
showEnableTouchExplorationDialog(final Service service)1311     private void showEnableTouchExplorationDialog(final Service service) {
1312         synchronized (mLock) {
1313             String label = service.mResolveInfo.loadLabel(
1314             mContext.getPackageManager()).toString();
1315 
1316             final UserState state = getCurrentUserStateLocked();
1317             if (state.mIsTouchExplorationEnabled) {
1318                 return;
1319             }
1320             if (mEnableTouchExplorationDialog != null
1321                     && mEnableTouchExplorationDialog.isShowing()) {
1322                 return;
1323             }
1324             mEnableTouchExplorationDialog = new AlertDialog.Builder(mContext)
1325                 .setIconAttribute(android.R.attr.alertDialogIcon)
1326                 .setPositiveButton(android.R.string.ok, new OnClickListener() {
1327                      @Override
1328                      public void onClick(DialogInterface dialog, int which) {
1329                          // The user allowed the service to toggle touch exploration.
1330                          state.mTouchExplorationGrantedServices.add(service.mComponentName);
1331                          persistComponentNamesToSettingLocked(
1332                                  Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
1333                                  state.mTouchExplorationGrantedServices, state.mUserId);
1334                          // Enable touch exploration.
1335                          UserState userState = getUserStateLocked(service.mUserId);
1336                          userState.mIsTouchExplorationEnabled = true;
1337                          Settings.Secure.putIntForUser(mContext.getContentResolver(),
1338                                  Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1,
1339                                  service.mUserId);
1340                          onUserStateChangedLocked(userState);
1341                      }
1342                  })
1343                  .setNegativeButton(android.R.string.cancel, new OnClickListener() {
1344                      @Override
1345                      public void onClick(DialogInterface dialog, int which) {
1346                          dialog.dismiss();
1347                      }
1348                  })
1349                  .setTitle(R.string.enable_explore_by_touch_warning_title)
1350                  .setMessage(mContext.getString(
1351                          R.string.enable_explore_by_touch_warning_message, label))
1352                  .create();
1353              mEnableTouchExplorationDialog.getWindow().setType(
1354                      WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1355              mEnableTouchExplorationDialog.getWindow().getAttributes().privateFlags
1356                      |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
1357              mEnableTouchExplorationDialog.setCanceledOnTouchOutside(true);
1358              mEnableTouchExplorationDialog.show();
1359         }
1360     }
1361 
onUserStateChangedLocked(UserState userState)1362     private void onUserStateChangedLocked(UserState userState) {
1363         // TODO: Remove this hack
1364         mInitialized = true;
1365         updateLegacyCapabilitiesLocked(userState);
1366         updateServicesLocked(userState);
1367         updateWindowsForAccessibilityCallbackLocked(userState);
1368         updateAccessibilityFocusBehaviorLocked(userState);
1369         updateFilterKeyEventsLocked(userState);
1370         updateTouchExplorationLocked(userState);
1371         updateEnhancedWebAccessibilityLocked(userState);
1372         updateDisplayColorAdjustmentSettingsLocked(userState);
1373         scheduleUpdateInputFilter(userState);
1374         scheduleUpdateClientsIfNeededLocked(userState);
1375     }
1376 
updateAccessibilityFocusBehaviorLocked(UserState userState)1377     private void updateAccessibilityFocusBehaviorLocked(UserState userState) {
1378         // If there is no service that can operate with interactive windows
1379         // then we keep the old behavior where a window loses accessibility
1380         // focus if it is no longer active. This still changes the behavior
1381         // for services that do not operate with interactive windows and run
1382         // at the same time as the one(s) which does. In practice however,
1383         // there is only one service that uses accessibility focus and it
1384         // is typically the one that operates with interactive windows, So,
1385         // this is fine. Note that to allow a service to work across windows
1386         // we have to allow accessibility focus stay in any of them. Sigh...
1387         List<Service> boundServices = userState.mBoundServices;
1388         final int boundServiceCount = boundServices.size();
1389         for (int i = 0; i < boundServiceCount; i++) {
1390             Service boundService = boundServices.get(i);
1391             if (boundService.canRetrieveInteractiveWindowsLocked()) {
1392                 userState.mAccessibilityFocusOnlyInActiveWindow = false;
1393                 return;
1394             }
1395         }
1396         userState.mAccessibilityFocusOnlyInActiveWindow = true;
1397     }
1398 
updateWindowsForAccessibilityCallbackLocked(UserState userState)1399     private void updateWindowsForAccessibilityCallbackLocked(UserState userState) {
1400         if (userState.mIsAccessibilityEnabled) {
1401             // We observe windows for accessibility only if there is at least
1402             // one bound service that can retrieve window content that specified
1403             // it is interested in accessing such windows. For services that are
1404             // binding we do an update pass after each bind event, so we run this
1405             // code and register the callback if needed.
1406             boolean boundServiceCanRetrieveInteractiveWindows = false;
1407 
1408             List<Service> boundServices = userState.mBoundServices;
1409             final int boundServiceCount = boundServices.size();
1410             for (int i = 0; i < boundServiceCount; i++) {
1411                 Service boundService = boundServices.get(i);
1412                 if (boundService.canRetrieveInteractiveWindowsLocked()) {
1413                     boundServiceCanRetrieveInteractiveWindows = true;
1414                     break;
1415                 }
1416             }
1417 
1418             if (boundServiceCanRetrieveInteractiveWindows) {
1419                 if (mWindowsForAccessibilityCallback == null) {
1420                     mWindowsForAccessibilityCallback = new WindowsForAccessibilityCallback();
1421                     mWindowManagerService.setWindowsForAccessibilityCallback(
1422                             mWindowsForAccessibilityCallback);
1423                 }
1424                 return;
1425             }
1426         }
1427 
1428         if (mWindowsForAccessibilityCallback != null) {
1429             mWindowsForAccessibilityCallback = null;
1430             mWindowManagerService.setWindowsForAccessibilityCallback(null);
1431             // Drop all windows we know about.
1432             mSecurityPolicy.clearWindowsLocked();
1433         }
1434     }
1435 
updateLegacyCapabilitiesLocked(UserState userState)1436     private void updateLegacyCapabilitiesLocked(UserState userState) {
1437         // Up to JB-MR1 we had a white list with services that can enable touch
1438         // exploration. When a service is first started we show a dialog to the
1439         // use to get a permission to white list the service.
1440         final int installedServiceCount = userState.mInstalledServices.size();
1441         for (int i = 0; i < installedServiceCount; i++) {
1442             AccessibilityServiceInfo serviceInfo = userState.mInstalledServices.get(i);
1443             ResolveInfo resolveInfo = serviceInfo.getResolveInfo();
1444             if ((serviceInfo.getCapabilities()
1445                         & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) == 0
1446                     && resolveInfo.serviceInfo.applicationInfo.targetSdkVersion
1447                         <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
1448                 ComponentName componentName = new ComponentName(
1449                         resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
1450                 if (userState.mTouchExplorationGrantedServices.contains(componentName)) {
1451                     serviceInfo.setCapabilities(serviceInfo.getCapabilities()
1452                             | AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION);
1453                 }
1454             }
1455         }
1456     }
1457 
updateFilterKeyEventsLocked(UserState userState)1458     private void updateFilterKeyEventsLocked(UserState userState) {
1459         final int serviceCount = userState.mBoundServices.size();
1460         for (int i = 0; i < serviceCount; i++) {
1461             Service service = userState.mBoundServices.get(i);
1462             if (service.mRequestFilterKeyEvents
1463                     && (service.mAccessibilityServiceInfo.getCapabilities()
1464                             & AccessibilityServiceInfo
1465                             .CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) != 0) {
1466                 userState.mIsFilterKeyEventsEnabled = true;
1467                 return;
1468             }
1469         }
1470         userState.mIsFilterKeyEventsEnabled = false;
1471     }
1472 
updateServicesLocked(UserState userState)1473     private void updateServicesLocked(UserState userState) {
1474         if (userState.mIsAccessibilityEnabled) {
1475             manageServicesLocked(userState);
1476         } else {
1477             unbindAllServicesLocked(userState);
1478         }
1479     }
1480 
readConfigurationForUserStateLocked(UserState userState)1481     private boolean readConfigurationForUserStateLocked(UserState userState) {
1482         boolean somthingChanged = readAccessibilityEnabledSettingLocked(userState);
1483         somthingChanged |= readInstalledAccessibilityServiceLocked(userState);
1484         somthingChanged |= readEnabledAccessibilityServicesLocked(userState);
1485         somthingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState);
1486         somthingChanged |= readTouchExplorationEnabledSettingLocked(userState);
1487         somthingChanged |= readHighTextContrastEnabledSettingLocked(userState);
1488         somthingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState);
1489         somthingChanged |= readDisplayMagnificationEnabledSettingLocked(userState);
1490         somthingChanged |= readDisplayColorAdjustmentSettingsLocked(userState);
1491         return somthingChanged;
1492     }
1493 
readAccessibilityEnabledSettingLocked(UserState userState)1494     private boolean readAccessibilityEnabledSettingLocked(UserState userState) {
1495         final boolean accessibilityEnabled = Settings.Secure.getIntForUser(
1496                mContext.getContentResolver(),
1497                Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId) == 1;
1498         if (accessibilityEnabled != userState.mIsAccessibilityEnabled) {
1499             userState.mIsAccessibilityEnabled = accessibilityEnabled;
1500             return true;
1501         }
1502         return false;
1503     }
1504 
readTouchExplorationEnabledSettingLocked(UserState userState)1505     private boolean readTouchExplorationEnabledSettingLocked(UserState userState) {
1506         final boolean touchExplorationEnabled = Settings.Secure.getIntForUser(
1507                 mContext.getContentResolver(),
1508                 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId) == 1;
1509         if (touchExplorationEnabled != userState.mIsTouchExplorationEnabled) {
1510             userState.mIsTouchExplorationEnabled = touchExplorationEnabled;
1511             return true;
1512         }
1513         return false;
1514     }
1515 
readDisplayMagnificationEnabledSettingLocked(UserState userState)1516     private boolean readDisplayMagnificationEnabledSettingLocked(UserState userState) {
1517         final boolean displayMagnificationEnabled = Settings.Secure.getIntForUser(
1518                 mContext.getContentResolver(),
1519                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
1520                 0, userState.mUserId) == 1;
1521         if (displayMagnificationEnabled != userState.mIsDisplayMagnificationEnabled) {
1522             userState.mIsDisplayMagnificationEnabled = displayMagnificationEnabled;
1523             return true;
1524         }
1525         return false;
1526     }
1527 
readEnhancedWebAccessibilityEnabledChangedLocked(UserState userState)1528     private boolean readEnhancedWebAccessibilityEnabledChangedLocked(UserState userState) {
1529          final boolean enhancedWeAccessibilityEnabled = Settings.Secure.getIntForUser(
1530                 mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION,
1531                 0, userState.mUserId) == 1;
1532          if (enhancedWeAccessibilityEnabled != userState.mIsEnhancedWebAccessibilityEnabled) {
1533              userState.mIsEnhancedWebAccessibilityEnabled = enhancedWeAccessibilityEnabled;
1534              return true;
1535          }
1536          return false;
1537     }
1538 
readDisplayColorAdjustmentSettingsLocked(UserState userState)1539     private boolean readDisplayColorAdjustmentSettingsLocked(UserState userState) {
1540         final boolean displayAdjustmentsEnabled = DisplayAdjustmentUtils.hasAdjustments(mContext,
1541                 userState.mUserId);
1542         if (displayAdjustmentsEnabled != userState.mHasDisplayColorAdjustment) {
1543             userState.mHasDisplayColorAdjustment = displayAdjustmentsEnabled;
1544             return true;
1545         }
1546         // If display adjustment is enabled, always assume there was a change in
1547         // the adjustment settings.
1548         return displayAdjustmentsEnabled;
1549     }
1550 
readHighTextContrastEnabledSettingLocked(UserState userState)1551     private boolean readHighTextContrastEnabledSettingLocked(UserState userState) {
1552         final boolean highTextContrastEnabled = Settings.Secure.getIntForUser(
1553                 mContext.getContentResolver(),
1554                 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, 0,
1555                 userState.mUserId) == 1;
1556         if (highTextContrastEnabled != userState.mIsTextHighContrastEnabled) {
1557             userState.mIsTextHighContrastEnabled = highTextContrastEnabled;
1558             return true;
1559         }
1560         return false;
1561     }
1562 
updateTouchExplorationLocked(UserState userState)1563     private void updateTouchExplorationLocked(UserState userState) {
1564         boolean enabled = false;
1565         final int serviceCount = userState.mBoundServices.size();
1566         for (int i = 0; i < serviceCount; i++) {
1567             Service service = userState.mBoundServices.get(i);
1568             if (canRequestAndRequestsTouchExplorationLocked(service)) {
1569                 enabled = true;
1570                 break;
1571             }
1572         }
1573         if (enabled != userState.mIsTouchExplorationEnabled) {
1574             userState.mIsTouchExplorationEnabled = enabled;
1575             Settings.Secure.putIntForUser(mContext.getContentResolver(),
1576                     Settings.Secure.TOUCH_EXPLORATION_ENABLED, enabled ? 1 : 0,
1577                     userState.mUserId);
1578         }
1579     }
1580 
canRequestAndRequestsTouchExplorationLocked(Service service)1581     private boolean canRequestAndRequestsTouchExplorationLocked(Service service) {
1582         // Service not ready or cannot request the feature - well nothing to do.
1583         if (!service.canReceiveEventsLocked() || !service.mRequestTouchExplorationMode) {
1584             return false;
1585         }
1586         // UI test automation service can always enable it.
1587         if (service.mIsAutomation) {
1588             return true;
1589         }
1590         if (service.mResolveInfo.serviceInfo.applicationInfo.targetSdkVersion
1591                 <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
1592             // Up to JB-MR1 we had a white list with services that can enable touch
1593             // exploration. When a service is first started we show a dialog to the
1594             // use to get a permission to white list the service.
1595             UserState userState = getUserStateLocked(service.mUserId);
1596             if (userState.mTouchExplorationGrantedServices.contains(service.mComponentName)) {
1597                 return true;
1598             } else if (mEnableTouchExplorationDialog == null
1599                     || !mEnableTouchExplorationDialog.isShowing()) {
1600                 mMainHandler.obtainMessage(
1601                         MainHandler.MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG,
1602                         service).sendToTarget();
1603             }
1604         } else {
1605             // Starting in JB-MR2 we request an accessibility service to declare
1606             // certain capabilities in its meta-data to allow it to enable the
1607             // corresponding features.
1608             if ((service.mAccessibilityServiceInfo.getCapabilities()
1609                     & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) != 0) {
1610                 return true;
1611             }
1612         }
1613         return false;
1614     }
1615 
updateEnhancedWebAccessibilityLocked(UserState userState)1616     private void updateEnhancedWebAccessibilityLocked(UserState userState) {
1617         boolean enabled = false;
1618         final int serviceCount = userState.mBoundServices.size();
1619         for (int i = 0; i < serviceCount; i++) {
1620             Service service = userState.mBoundServices.get(i);
1621             if (canRequestAndRequestsEnhancedWebAccessibilityLocked(service)) {
1622                 enabled = true;
1623                 break;
1624             }
1625         }
1626         if (enabled != userState.mIsEnhancedWebAccessibilityEnabled) {
1627             userState.mIsEnhancedWebAccessibilityEnabled = enabled;
1628             Settings.Secure.putIntForUser(mContext.getContentResolver(),
1629                     Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, enabled ? 1 : 0,
1630                     userState.mUserId);
1631         }
1632     }
1633 
canRequestAndRequestsEnhancedWebAccessibilityLocked(Service service)1634     private boolean canRequestAndRequestsEnhancedWebAccessibilityLocked(Service service) {
1635         if (!service.canReceiveEventsLocked() || !service.mRequestEnhancedWebAccessibility ) {
1636             return false;
1637         }
1638         if (service.mIsAutomation || (service.mAccessibilityServiceInfo.getCapabilities()
1639                & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0) {
1640             return true;
1641         }
1642         return false;
1643     }
1644 
updateDisplayColorAdjustmentSettingsLocked(UserState userState)1645     private void updateDisplayColorAdjustmentSettingsLocked(UserState userState) {
1646         DisplayAdjustmentUtils.applyAdjustments(mContext, userState.mUserId);
1647     }
1648 
hasRunningServicesLocked(UserState userState)1649     private boolean hasRunningServicesLocked(UserState userState) {
1650         return !userState.mBoundServices.isEmpty() || !userState.mBindingServices.isEmpty();
1651     }
1652 
getCompatibleMagnificationSpecLocked(int windowId)1653     private MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) {
1654         IBinder windowToken = mGlobalWindowTokens.get(windowId);
1655         if (windowToken == null) {
1656             windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId);
1657         }
1658         if (windowToken != null) {
1659             return mWindowManagerService.getCompatibleMagnificationSpecForWindow(
1660                     windowToken);
1661         }
1662         return null;
1663     }
1664 
1665     @Override
dump(FileDescriptor fd, final PrintWriter pw, String[] args)1666     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
1667         mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
1668         synchronized (mLock) {
1669             pw.println("ACCESSIBILITY MANAGER (dumpsys accessibility)");
1670             pw.println();
1671             final int userCount = mUserStates.size();
1672             for (int i = 0; i < userCount; i++) {
1673                 UserState userState = mUserStates.valueAt(i);
1674                 pw.append("User state[attributes:{id=" + userState.mUserId);
1675                 pw.append(", currentUser=" + (userState.mUserId == mCurrentUserId));
1676                 pw.append(", accessibilityEnabled=" + userState.mIsAccessibilityEnabled);
1677                 pw.append(", touchExplorationEnabled=" + userState.mIsTouchExplorationEnabled);
1678                 pw.append(", displayMagnificationEnabled="
1679                         + userState.mIsDisplayMagnificationEnabled);
1680                 if (userState.mUiAutomationService != null) {
1681                     pw.append(", ");
1682                     userState.mUiAutomationService.dump(fd, pw, args);
1683                     pw.println();
1684                 }
1685                 pw.append("}");
1686                 pw.println();
1687                 pw.append("           services:{");
1688                 final int serviceCount = userState.mBoundServices.size();
1689                 for (int j = 0; j < serviceCount; j++) {
1690                     if (j > 0) {
1691                         pw.append(", ");
1692                         pw.println();
1693                         pw.append("                     ");
1694                     }
1695                     Service service = userState.mBoundServices.get(j);
1696                     service.dump(fd, pw, args);
1697                 }
1698                 pw.println("}]");
1699                 pw.println();
1700             }
1701             if (mSecurityPolicy.mWindows != null) {
1702                 final int windowCount = mSecurityPolicy.mWindows.size();
1703                 for (int j = 0; j < windowCount; j++) {
1704                     if (j > 0) {
1705                         pw.append(',');
1706                         pw.println();
1707                     }
1708                     pw.append("Window[");
1709                     AccessibilityWindowInfo window = mSecurityPolicy.mWindows.get(j);
1710                     pw.append(window.toString());
1711                     pw.append(']');
1712                 }
1713             }
1714         }
1715     }
1716 
1717     private class AccessibilityConnectionWrapper implements DeathRecipient {
1718         private final int mWindowId;
1719         private final int mUserId;
1720         private final IAccessibilityInteractionConnection mConnection;
1721 
AccessibilityConnectionWrapper(int windowId, IAccessibilityInteractionConnection connection, int userId)1722         public AccessibilityConnectionWrapper(int windowId,
1723                 IAccessibilityInteractionConnection connection, int userId) {
1724             mWindowId = windowId;
1725             mUserId = userId;
1726             mConnection = connection;
1727         }
1728 
linkToDeath()1729         public void linkToDeath() throws RemoteException {
1730             mConnection.asBinder().linkToDeath(this, 0);
1731         }
1732 
unlinkToDeath()1733         public void unlinkToDeath() {
1734             mConnection.asBinder().unlinkToDeath(this, 0);
1735         }
1736 
1737         @Override
binderDied()1738         public void binderDied() {
1739             unlinkToDeath();
1740             synchronized (mLock) {
1741                 removeAccessibilityInteractionConnectionLocked(mWindowId, mUserId);
1742             }
1743         }
1744     }
1745 
1746     private final class MainHandler extends Handler {
1747         public static final int MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER = 1;
1748         public static final int MSG_SEND_STATE_TO_CLIENTS = 2;
1749         public static final int MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER = 3;
1750         public static final int MSG_ANNOUNCE_NEW_USER_IF_NEEDED = 5;
1751         public static final int MSG_UPDATE_INPUT_FILTER = 6;
1752         public static final int MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG = 7;
1753         public static final int MSG_SEND_KEY_EVENT_TO_INPUT_FILTER = 8;
1754         public static final int MSG_CLEAR_ACCESSIBILITY_FOCUS = 9;
1755 
MainHandler(Looper looper)1756         public MainHandler(Looper looper) {
1757             super(looper);
1758         }
1759 
1760         @Override
handleMessage(Message msg)1761         public void handleMessage(Message msg) {
1762             final int type = msg.what;
1763             switch (type) {
1764                 case MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER: {
1765                     AccessibilityEvent event = (AccessibilityEvent) msg.obj;
1766                     synchronized (mLock) {
1767                         if (mHasInputFilter && mInputFilter != null) {
1768                             mInputFilter.notifyAccessibilityEvent(event);
1769                         }
1770                     }
1771                     event.recycle();
1772                 } break;
1773 
1774                 case MSG_SEND_KEY_EVENT_TO_INPUT_FILTER: {
1775                     KeyEvent event = (KeyEvent) msg.obj;
1776                     final int policyFlags = msg.arg1;
1777                     synchronized (mLock) {
1778                         if (mHasInputFilter && mInputFilter != null) {
1779                             mInputFilter.sendInputEvent(event, policyFlags);
1780                         }
1781                     }
1782                     event.recycle();
1783                 } break;
1784 
1785                 case MSG_SEND_STATE_TO_CLIENTS: {
1786                     final int clientState = msg.arg1;
1787                     final int userId = msg.arg2;
1788                     sendStateToClients(clientState, mGlobalClients);
1789                     sendStateToClientsForUser(clientState, userId);
1790                 } break;
1791 
1792                 case MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER: {
1793                     final int userId = msg.arg1;
1794                     sendStateToClientsForUser(0, userId);
1795                 } break;
1796 
1797                 case MSG_ANNOUNCE_NEW_USER_IF_NEEDED: {
1798                     announceNewUserIfNeeded();
1799                 } break;
1800 
1801                 case MSG_UPDATE_INPUT_FILTER: {
1802                     UserState userState = (UserState) msg.obj;
1803                     updateInputFilter(userState);
1804                 } break;
1805 
1806                 case MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG: {
1807                     Service service = (Service) msg.obj;
1808                     showEnableTouchExplorationDialog(service);
1809                 } break;
1810 
1811                 case MSG_CLEAR_ACCESSIBILITY_FOCUS: {
1812                     final int windowId = msg.arg1;
1813                     InteractionBridge bridge;
1814                     synchronized (mLock) {
1815                         bridge = getInteractionBridgeLocked();
1816                     }
1817                     bridge.clearAccessibilityFocusNotLocked(windowId);
1818                 } break;
1819             }
1820         }
1821 
announceNewUserIfNeeded()1822         private void announceNewUserIfNeeded() {
1823             synchronized (mLock) {
1824                 UserState userState = getCurrentUserStateLocked();
1825                 if (userState.mIsAccessibilityEnabled) {
1826                     UserManager userManager = (UserManager) mContext.getSystemService(
1827                             Context.USER_SERVICE);
1828                     String message = mContext.getString(R.string.user_switched,
1829                             userManager.getUserInfo(mCurrentUserId).name);
1830                     AccessibilityEvent event = AccessibilityEvent.obtain(
1831                             AccessibilityEvent.TYPE_ANNOUNCEMENT);
1832                     event.getText().add(message);
1833                     sendAccessibilityEvent(event, mCurrentUserId);
1834                 }
1835             }
1836         }
1837 
sendStateToClientsForUser(int clientState, int userId)1838         private void sendStateToClientsForUser(int clientState, int userId) {
1839             final UserState userState;
1840             synchronized (mLock) {
1841                 userState = getUserStateLocked(userId);
1842             }
1843             sendStateToClients(clientState, userState.mClients);
1844         }
1845 
sendStateToClients(int clientState, RemoteCallbackList<IAccessibilityManagerClient> clients)1846         private void sendStateToClients(int clientState,
1847                 RemoteCallbackList<IAccessibilityManagerClient> clients) {
1848             try {
1849                 final int userClientCount = clients.beginBroadcast();
1850                 for (int i = 0; i < userClientCount; i++) {
1851                     IAccessibilityManagerClient client = clients.getBroadcastItem(i);
1852                     try {
1853                         client.setState(clientState);
1854                     } catch (RemoteException re) {
1855                         /* ignore */
1856                     }
1857                 }
1858             } finally {
1859                 clients.finishBroadcast();
1860             }
1861         }
1862     }
1863 
obtainPendingEventLocked(KeyEvent event, int policyFlags, int sequence)1864     private PendingEvent obtainPendingEventLocked(KeyEvent event, int policyFlags, int sequence) {
1865         PendingEvent pendingEvent = mPendingEventPool.acquire();
1866         if (pendingEvent == null) {
1867             pendingEvent = new PendingEvent();
1868         }
1869         pendingEvent.event = event;
1870         pendingEvent.policyFlags = policyFlags;
1871         pendingEvent.sequence = sequence;
1872         return pendingEvent;
1873     }
1874 
recyclePendingEventLocked(PendingEvent pendingEvent)1875     private void recyclePendingEventLocked(PendingEvent pendingEvent) {
1876         pendingEvent.clear();
1877         mPendingEventPool.release(pendingEvent);
1878     }
1879 
findWindowIdLocked(IBinder token)1880     private int findWindowIdLocked(IBinder token) {
1881         final int globalIndex = mGlobalWindowTokens.indexOfValue(token);
1882         if (globalIndex >= 0) {
1883             return mGlobalWindowTokens.keyAt(globalIndex);
1884         }
1885         UserState userState = getCurrentUserStateLocked();
1886         final int userIndex = userState.mWindowTokens.indexOfValue(token);
1887         if (userIndex >= 0) {
1888             return userState.mWindowTokens.keyAt(userIndex);
1889         }
1890         return -1;
1891     }
1892 
ensureWindowsAvailableTimed()1893     private void ensureWindowsAvailableTimed() {
1894         synchronized (mLock) {
1895             if (mSecurityPolicy.mWindows != null) {
1896                 return;
1897             }
1898             // If we have no registered callback, update the state we
1899             // we may have to register one but it didn't happen yet.
1900             if (mWindowsForAccessibilityCallback == null) {
1901                 UserState userState = getCurrentUserStateLocked();
1902                 onUserStateChangedLocked(userState);
1903             }
1904             // We have no windows but do not care about them, done.
1905             if (mWindowsForAccessibilityCallback == null) {
1906                 return;
1907             }
1908 
1909             // Wait for the windows with a timeout.
1910             final long startMillis = SystemClock.uptimeMillis();
1911             while (mSecurityPolicy.mWindows == null) {
1912                 final long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
1913                 final long remainMillis = WAIT_WINDOWS_TIMEOUT_MILLIS - elapsedMillis;
1914                 if (remainMillis <= 0) {
1915                     return;
1916                 }
1917                 try {
1918                     mLock.wait(remainMillis);
1919                 } catch (InterruptedException ie) {
1920                     /* ignore */
1921                 }
1922             }
1923         }
1924     }
1925 
1926     /**
1927      * This class represents an accessibility service. It stores all per service
1928      * data required for the service management, provides API for starting/stopping the
1929      * service and is responsible for adding/removing the service in the data structures
1930      * for service management. The class also exposes configuration interface that is
1931      * passed to the service it represents as soon it is bound. It also serves as the
1932      * connection for the service.
1933      */
1934     class Service extends IAccessibilityServiceConnection.Stub
1935             implements ServiceConnection, DeathRecipient {;
1936 
1937         final int mUserId;
1938 
1939         int mId = 0;
1940 
1941         AccessibilityServiceInfo mAccessibilityServiceInfo;
1942 
1943         IBinder mService;
1944 
1945         IAccessibilityServiceClient mServiceInterface;
1946 
1947         int mEventTypes;
1948 
1949         int mFeedbackType;
1950 
1951         Set<String> mPackageNames = new HashSet<>();
1952 
1953         boolean mIsDefault;
1954 
1955         boolean mRequestTouchExplorationMode;
1956 
1957         boolean mRequestEnhancedWebAccessibility;
1958 
1959         boolean mRequestFilterKeyEvents;
1960 
1961         boolean mRetrieveInteractiveWindows;
1962 
1963         int mFetchFlags;
1964 
1965         long mNotificationTimeout;
1966 
1967         ComponentName mComponentName;
1968 
1969         Intent mIntent;
1970 
1971         boolean mIsAutomation;
1972 
1973         final ResolveInfo mResolveInfo;
1974 
1975         final IBinder mOverlayWindowToken = new Binder();
1976 
1977         // the events pending events to be dispatched to this service
1978         final SparseArray<AccessibilityEvent> mPendingEvents =
1979             new SparseArray<>();
1980 
1981         final KeyEventDispatcher mKeyEventDispatcher = new KeyEventDispatcher();
1982 
1983         boolean mWasConnectedAndDied;
1984 
1985         // Handler only for dispatching accessibility events since we use event
1986         // types as message types allowing us to remove messages per event type.
1987         public Handler mEventDispatchHandler = new Handler(mMainHandler.getLooper()) {
1988             @Override
1989             public void handleMessage(Message message) {
1990                 final int eventType =  message.what;
1991                 notifyAccessibilityEventInternal(eventType);
1992             }
1993         };
1994 
1995         // Handler for scheduling method invocations on the main thread.
1996         public InvocationHandler mInvocationHandler = new InvocationHandler(
1997                 mMainHandler.getLooper());
1998 
Service(int userId, ComponentName componentName, AccessibilityServiceInfo accessibilityServiceInfo)1999         public Service(int userId, ComponentName componentName,
2000                 AccessibilityServiceInfo accessibilityServiceInfo) {
2001             mUserId = userId;
2002             mResolveInfo = accessibilityServiceInfo.getResolveInfo();
2003             mId = sIdCounter++;
2004             mComponentName = componentName;
2005             mAccessibilityServiceInfo = accessibilityServiceInfo;
2006             mIsAutomation = (sFakeAccessibilityServiceComponentName.equals(componentName));
2007             if (!mIsAutomation) {
2008                 mIntent = new Intent().setComponent(mComponentName);
2009                 mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
2010                         com.android.internal.R.string.accessibility_binding_label);
2011                 mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
2012                         mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0));
2013             }
2014             setDynamicallyConfigurableProperties(accessibilityServiceInfo);
2015         }
2016 
setDynamicallyConfigurableProperties(AccessibilityServiceInfo info)2017         public void setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) {
2018             mEventTypes = info.eventTypes;
2019             mFeedbackType = info.feedbackType;
2020             String[] packageNames = info.packageNames;
2021             if (packageNames != null) {
2022                 mPackageNames.addAll(Arrays.asList(packageNames));
2023             }
2024             mNotificationTimeout = info.notificationTimeout;
2025             mIsDefault = (info.flags & DEFAULT) != 0;
2026 
2027             if (mIsAutomation || info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion
2028                     >= Build.VERSION_CODES.JELLY_BEAN) {
2029                 if ((info.flags & AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0) {
2030                     mFetchFlags |= AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
2031                 } else {
2032                     mFetchFlags &= ~AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
2033                 }
2034             }
2035 
2036             if ((info.flags & AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS) != 0) {
2037                 mFetchFlags |= AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS;
2038             } else {
2039                 mFetchFlags &= ~AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS;
2040             }
2041 
2042             mRequestTouchExplorationMode = (info.flags
2043                     & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
2044             mRequestEnhancedWebAccessibility = (info.flags
2045                     & AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0;
2046             mRequestFilterKeyEvents = (info.flags
2047                     & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0;
2048             mRetrieveInteractiveWindows = (info.flags
2049                     & AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS) != 0;
2050         }
2051 
2052         /**
2053          * Binds to the accessibility service.
2054          *
2055          * @return True if binding is successful.
2056          */
bindLocked()2057         public boolean bindLocked() {
2058             UserState userState = getUserStateLocked(mUserId);
2059             if (!mIsAutomation) {
2060                 if (mService == null && mContext.bindServiceAsUser(
2061                         mIntent, this,
2062                         Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
2063                         new UserHandle(mUserId))) {
2064                     userState.mBindingServices.add(mComponentName);
2065                 }
2066             } else {
2067                 userState.mBindingServices.add(mComponentName);
2068                 mService = userState.mUiAutomationServiceClient.asBinder();
2069                 mMainHandler.post(new Runnable() {
2070                     @Override
2071                     public void run() {
2072                         // Simulate asynchronous connection since in onServiceConnected
2073                         // we may modify the state data in case of an error but bind is
2074                         // called while iterating over the data and bad things can happen.
2075                         onServiceConnected(mComponentName, mService);
2076                     }
2077                 });
2078                 userState.mUiAutomationService = this;
2079             }
2080             return false;
2081         }
2082 
2083         /**
2084          * Unbinds form the accessibility service and removes it from the data
2085          * structures for service management.
2086          *
2087          * @return True if unbinding is successful.
2088          */
unbindLocked()2089         public boolean unbindLocked() {
2090             if (mService == null) {
2091                 return false;
2092             }
2093             UserState userState = getUserStateLocked(mUserId);
2094             mKeyEventDispatcher.flush();
2095             if (!mIsAutomation) {
2096                 mContext.unbindService(this);
2097             } else {
2098                 userState.destroyUiAutomationService();
2099             }
2100             removeServiceLocked(this, userState);
2101             resetLocked();
2102             return true;
2103         }
2104 
canReceiveEventsLocked()2105         public boolean canReceiveEventsLocked() {
2106             return (mEventTypes != 0 && mFeedbackType != 0 && mService != null);
2107         }
2108 
2109         @Override
setOnKeyEventResult(boolean handled, int sequence)2110         public void setOnKeyEventResult(boolean handled, int sequence) {
2111             mKeyEventDispatcher.setOnKeyEventResult(handled, sequence);
2112         }
2113 
2114         @Override
getServiceInfo()2115         public AccessibilityServiceInfo getServiceInfo() {
2116             synchronized (mLock) {
2117                 return mAccessibilityServiceInfo;
2118             }
2119         }
2120 
canRetrieveInteractiveWindowsLocked()2121         public boolean canRetrieveInteractiveWindowsLocked() {
2122             return mSecurityPolicy.canRetrieveWindowContentLocked(this)
2123                     && mRetrieveInteractiveWindows;
2124         }
2125 
2126         @Override
setServiceInfo(AccessibilityServiceInfo info)2127         public void setServiceInfo(AccessibilityServiceInfo info) {
2128             final long identity = Binder.clearCallingIdentity();
2129             try {
2130                 synchronized (mLock) {
2131                     // If the XML manifest had data to configure the service its info
2132                     // should be already set. In such a case update only the dynamically
2133                     // configurable properties.
2134                     AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo;
2135                     if (oldInfo != null) {
2136                         oldInfo.updateDynamicallyConfigurableProperties(info);
2137                         setDynamicallyConfigurableProperties(oldInfo);
2138                     } else {
2139                         setDynamicallyConfigurableProperties(info);
2140                     }
2141                     UserState userState = getUserStateLocked(mUserId);
2142                     onUserStateChangedLocked(userState);
2143                 }
2144             } finally {
2145                 Binder.restoreCallingIdentity(identity);
2146             }
2147         }
2148 
2149         @Override
onServiceConnected(ComponentName componentName, IBinder service)2150         public void onServiceConnected(ComponentName componentName, IBinder service) {
2151             synchronized (mLock) {
2152                 mService = service;
2153                 mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
2154                 UserState userState = getUserStateLocked(mUserId);
2155                 addServiceLocked(this, userState);
2156                 if (userState.mBindingServices.contains(mComponentName) || mWasConnectedAndDied) {
2157                     userState.mBindingServices.remove(mComponentName);
2158                     mWasConnectedAndDied = false;
2159                     try {
2160                        mServiceInterface.init(this, mId, mOverlayWindowToken);
2161                        onUserStateChangedLocked(userState);
2162                     } catch (RemoteException re) {
2163                         Slog.w(LOG_TAG, "Error while setting connection for service: "
2164                                 + service, re);
2165                         binderDied();
2166                     }
2167                 } else {
2168                     binderDied();
2169                 }
2170             }
2171         }
2172 
2173         @Override
getWindows()2174         public List<AccessibilityWindowInfo> getWindows() {
2175             ensureWindowsAvailableTimed();
2176             synchronized (mLock) {
2177                 // We treat calls from a profile as if made by its perent as profiles
2178                 // share the accessibility state of the parent. The call below
2179                 // performs the current profile parent resolution.
2180                 final int resolvedUserId = mSecurityPolicy
2181                         .resolveCallingUserIdEnforcingPermissionsLocked(
2182                                 UserHandle.USER_CURRENT);
2183                 if (resolvedUserId != mCurrentUserId) {
2184                     return null;
2185                 }
2186                 final boolean permissionGranted =
2187                         mSecurityPolicy.canRetrieveWindowsLocked(this);
2188                 if (!permissionGranted) {
2189                     return null;
2190                 }
2191                 if (mSecurityPolicy.mWindows == null) {
2192                     return null;
2193                 }
2194                 List<AccessibilityWindowInfo> windows = new ArrayList<>();
2195                 final int windowCount = mSecurityPolicy.mWindows.size();
2196                 for (int i = 0; i < windowCount; i++) {
2197                     AccessibilityWindowInfo window = mSecurityPolicy.mWindows.get(i);
2198                     AccessibilityWindowInfo windowClone =
2199                             AccessibilityWindowInfo.obtain(window);
2200                     windowClone.setConnectionId(mId);
2201                     windows.add(windowClone);
2202                 }
2203                 return windows;
2204             }
2205         }
2206 
2207         @Override
getWindow(int windowId)2208         public AccessibilityWindowInfo getWindow(int windowId) {
2209             ensureWindowsAvailableTimed();
2210             synchronized (mLock) {
2211                 // We treat calls from a profile as if made by its parent as profiles
2212                 // share the accessibility state of the parent. The call below
2213                 // performs the current profile parent resolution.
2214                 final int resolvedUserId = mSecurityPolicy
2215                         .resolveCallingUserIdEnforcingPermissionsLocked(
2216                                 UserHandle.USER_CURRENT);
2217                 if (resolvedUserId != mCurrentUserId) {
2218                     return null;
2219                 }
2220                 final boolean permissionGranted =
2221                         mSecurityPolicy.canRetrieveWindowsLocked(this);
2222                 if (!permissionGranted) {
2223                     return null;
2224                 }
2225                 AccessibilityWindowInfo window = mSecurityPolicy.findWindowById(windowId);
2226                 if (window != null) {
2227                     AccessibilityWindowInfo windowClone = AccessibilityWindowInfo.obtain(window);
2228                     windowClone.setConnectionId(mId);
2229                     return windowClone;
2230                 }
2231                 return null;
2232             }
2233         }
2234 
2235         @Override
findAccessibilityNodeInfosByViewId(int accessibilityWindowId, long accessibilityNodeId, String viewIdResName, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)2236         public boolean findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
2237                 long accessibilityNodeId, String viewIdResName, int interactionId,
2238                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
2239                 throws RemoteException {
2240             final int resolvedWindowId;
2241             IAccessibilityInteractionConnection connection = null;
2242             Region partialInteractiveRegion = Region.obtain();
2243             synchronized (mLock) {
2244                 // We treat calls from a profile as if made by its parent as profiles
2245                 // share the accessibility state of the parent. The call below
2246                 // performs the current profile parent resolution.
2247                 final int resolvedUserId = mSecurityPolicy
2248                         .resolveCallingUserIdEnforcingPermissionsLocked(
2249                                 UserHandle.USER_CURRENT);
2250                 if (resolvedUserId != mCurrentUserId) {
2251                     return false;
2252                 }
2253                 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
2254                 final boolean permissionGranted =
2255                         mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
2256                 if (!permissionGranted) {
2257                     return false;
2258                 } else {
2259                     connection = getConnectionLocked(resolvedWindowId);
2260                     if (connection == null) {
2261                         return false;
2262                     }
2263                 }
2264                 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
2265                         resolvedWindowId, partialInteractiveRegion)) {
2266                     partialInteractiveRegion.recycle();
2267                     partialInteractiveRegion = null;
2268                 }
2269             }
2270             final int interrogatingPid = Binder.getCallingPid();
2271             final long identityToken = Binder.clearCallingIdentity();
2272             MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
2273             try {
2274                 connection.findAccessibilityNodeInfosByViewId(accessibilityNodeId, viewIdResName,
2275                         partialInteractiveRegion, interactionId, callback, mFetchFlags,
2276                         interrogatingPid, interrogatingTid, spec);
2277                 return true;
2278             } catch (RemoteException re) {
2279                 if (DEBUG) {
2280                     Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId().");
2281                 }
2282             } finally {
2283                 Binder.restoreCallingIdentity(identityToken);
2284                 // Recycle if passed to another process.
2285                 if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
2286                     partialInteractiveRegion.recycle();
2287                 }
2288             }
2289             return false;
2290         }
2291 
2292         @Override
findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId, String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)2293         public boolean findAccessibilityNodeInfosByText(int accessibilityWindowId,
2294                 long accessibilityNodeId, String text, int interactionId,
2295                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
2296                 throws RemoteException {
2297             final int resolvedWindowId;
2298             IAccessibilityInteractionConnection connection = null;
2299             Region partialInteractiveRegion = Region.obtain();
2300             synchronized (mLock) {
2301                 // We treat calls from a profile as if made by its parent as profiles
2302                 // share the accessibility state of the parent. The call below
2303                 // performs the current profile parent resolution.
2304                 final int resolvedUserId = mSecurityPolicy
2305                         .resolveCallingUserIdEnforcingPermissionsLocked(
2306                                 UserHandle.USER_CURRENT);
2307                 if (resolvedUserId != mCurrentUserId) {
2308                     return false;
2309                 }
2310                 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
2311                 final boolean permissionGranted =
2312                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
2313                 if (!permissionGranted) {
2314                     return false;
2315                 } else {
2316                     connection = getConnectionLocked(resolvedWindowId);
2317                     if (connection == null) {
2318                         return false;
2319                     }
2320                 }
2321                 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
2322                         resolvedWindowId, partialInteractiveRegion)) {
2323                     partialInteractiveRegion.recycle();
2324                     partialInteractiveRegion = null;
2325                 }
2326             }
2327             final int interrogatingPid = Binder.getCallingPid();
2328             final long identityToken = Binder.clearCallingIdentity();
2329             MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
2330             try {
2331                 connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
2332                         partialInteractiveRegion, interactionId, callback, mFetchFlags,
2333                         interrogatingPid, interrogatingTid, spec);
2334                 return true;
2335             } catch (RemoteException re) {
2336                 if (DEBUG) {
2337                     Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()");
2338                 }
2339             } finally {
2340                 Binder.restoreCallingIdentity(identityToken);
2341                 // Recycle if passed to another process.
2342                 if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
2343                     partialInteractiveRegion.recycle();
2344                 }
2345             }
2346             return false;
2347         }
2348 
2349         @Override
findAccessibilityNodeInfoByAccessibilityId( int accessibilityWindowId, long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, long interrogatingTid)2350         public boolean findAccessibilityNodeInfoByAccessibilityId(
2351                 int accessibilityWindowId, long accessibilityNodeId, int interactionId,
2352                 IAccessibilityInteractionConnectionCallback callback, int flags,
2353                 long interrogatingTid) throws RemoteException {
2354             final int resolvedWindowId;
2355             IAccessibilityInteractionConnection connection = null;
2356             Region partialInteractiveRegion = Region.obtain();
2357             synchronized (mLock) {
2358                 // We treat calls from a profile as if made by its parent as profiles
2359                 // share the accessibility state of the parent. The call below
2360                 // performs the current profile parent resolution.
2361                 final int resolvedUserId = mSecurityPolicy
2362                         .resolveCallingUserIdEnforcingPermissionsLocked(
2363                                 UserHandle.USER_CURRENT);
2364                 if (resolvedUserId != mCurrentUserId) {
2365                     return false;
2366                 }
2367                 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
2368                 final boolean permissionGranted =
2369                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
2370                 if (!permissionGranted) {
2371                     return false;
2372                 } else {
2373                     connection = getConnectionLocked(resolvedWindowId);
2374                     if (connection == null) {
2375                         return false;
2376                     }
2377                 }
2378                 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
2379                         resolvedWindowId, partialInteractiveRegion)) {
2380                     partialInteractiveRegion.recycle();
2381                     partialInteractiveRegion = null;
2382                 }
2383             }
2384             final int interrogatingPid = Binder.getCallingPid();
2385             final long identityToken = Binder.clearCallingIdentity();
2386             MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
2387             try {
2388                 connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId,
2389                         partialInteractiveRegion, interactionId, callback, mFetchFlags | flags,
2390                         interrogatingPid, interrogatingTid, spec);
2391                 return true;
2392             } catch (RemoteException re) {
2393                 if (DEBUG) {
2394                     Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
2395                 }
2396             } finally {
2397                 Binder.restoreCallingIdentity(identityToken);
2398                 // Recycle if passed to another process.
2399                 if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
2400                     partialInteractiveRegion.recycle();
2401                 }
2402             }
2403             return false;
2404         }
2405 
2406         @Override
findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)2407         public boolean findFocus(int accessibilityWindowId, long accessibilityNodeId,
2408                 int focusType, int interactionId,
2409                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
2410                 throws RemoteException {
2411             final int resolvedWindowId;
2412             IAccessibilityInteractionConnection connection = null;
2413             Region partialInteractiveRegion = Region.obtain();
2414             synchronized (mLock) {
2415                 // We treat calls from a profile as if made by its parent as profiles
2416                 // share the accessibility state of the parent. The call below
2417                 // performs the current profile parent resolution.
2418                 final int resolvedUserId = mSecurityPolicy
2419                         .resolveCallingUserIdEnforcingPermissionsLocked(
2420                                 UserHandle.USER_CURRENT);
2421                 if (resolvedUserId != mCurrentUserId) {
2422                     return false;
2423                 }
2424                 resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked(
2425                         accessibilityWindowId, focusType);
2426                 final boolean permissionGranted =
2427                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
2428                 if (!permissionGranted) {
2429                     return false;
2430                 } else {
2431                     connection = getConnectionLocked(resolvedWindowId);
2432                     if (connection == null) {
2433                         return false;
2434                     }
2435                 }
2436                 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
2437                         resolvedWindowId, partialInteractiveRegion)) {
2438                     partialInteractiveRegion.recycle();
2439                     partialInteractiveRegion = null;
2440                 }
2441             }
2442             final int interrogatingPid = Binder.getCallingPid();
2443             final long identityToken = Binder.clearCallingIdentity();
2444             MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
2445             try {
2446                 connection.findFocus(accessibilityNodeId, focusType, partialInteractiveRegion,
2447                         interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid,
2448                         spec);
2449                 return true;
2450             } catch (RemoteException re) {
2451                 if (DEBUG) {
2452                     Slog.e(LOG_TAG, "Error calling findFocus()");
2453                 }
2454             } finally {
2455                 Binder.restoreCallingIdentity(identityToken);
2456                 // Recycle if passed to another process.
2457                 if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
2458                     partialInteractiveRegion.recycle();
2459                 }
2460             }
2461             return false;
2462         }
2463 
2464         @Override
focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)2465         public boolean focusSearch(int accessibilityWindowId, long accessibilityNodeId,
2466                 int direction, int interactionId,
2467                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
2468                 throws RemoteException {
2469             final int resolvedWindowId;
2470             IAccessibilityInteractionConnection connection = null;
2471             Region partialInteractiveRegion = Region.obtain();
2472             synchronized (mLock) {
2473                 // We treat calls from a profile as if made by its parent as profiles
2474                 // share the accessibility state of the parent. The call below
2475                 // performs the current profile parent resolution.
2476                 final int resolvedUserId = mSecurityPolicy
2477                         .resolveCallingUserIdEnforcingPermissionsLocked(
2478                                 UserHandle.USER_CURRENT);
2479                 if (resolvedUserId != mCurrentUserId) {
2480                     return false;
2481                 }
2482                 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
2483                 final boolean permissionGranted =
2484                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
2485                 if (!permissionGranted) {
2486                     return false;
2487                 } else {
2488                     connection = getConnectionLocked(resolvedWindowId);
2489                     if (connection == null) {
2490                         return false;
2491                     }
2492                 }
2493                 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
2494                         resolvedWindowId, partialInteractiveRegion)) {
2495                     partialInteractiveRegion.recycle();
2496                     partialInteractiveRegion = null;
2497                 }
2498             }
2499             final int interrogatingPid = Binder.getCallingPid();
2500             final long identityToken = Binder.clearCallingIdentity();
2501             MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
2502             try {
2503                 connection.focusSearch(accessibilityNodeId, direction, partialInteractiveRegion,
2504                         interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid,
2505                         spec);
2506                 return true;
2507             } catch (RemoteException re) {
2508                 if (DEBUG) {
2509                     Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()");
2510                 }
2511             } finally {
2512                 Binder.restoreCallingIdentity(identityToken);
2513                 // Recycle if passed to another process.
2514                 if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
2515                     partialInteractiveRegion.recycle();
2516                 }
2517             }
2518             return false;
2519         }
2520 
2521         @Override
performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)2522         public boolean performAccessibilityAction(int accessibilityWindowId,
2523                 long accessibilityNodeId, int action, Bundle arguments, int interactionId,
2524                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
2525                 throws RemoteException {
2526             final int resolvedWindowId;
2527             IAccessibilityInteractionConnection connection = null;
2528             synchronized (mLock) {
2529                 // We treat calls from a profile as if made by its parent as profiles
2530                 // share the accessibility state of the parent. The call below
2531                 // performs the current profile parent resolution.
2532                 final int resolvedUserId = mSecurityPolicy
2533                         .resolveCallingUserIdEnforcingPermissionsLocked(
2534                                 UserHandle.USER_CURRENT);
2535                 if (resolvedUserId != mCurrentUserId) {
2536                     return false;
2537                 }
2538                 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
2539                 final boolean permissionGranted = mSecurityPolicy.canGetAccessibilityNodeInfoLocked(
2540                         this, resolvedWindowId);
2541                 if (!permissionGranted) {
2542                     return false;
2543                 } else {
2544                     connection = getConnectionLocked(resolvedWindowId);
2545                     if (connection == null) {
2546                         return false;
2547                     }
2548                 }
2549             }
2550             final int interrogatingPid = Binder.getCallingPid();
2551             final long identityToken = Binder.clearCallingIdentity();
2552             try {
2553                 connection.performAccessibilityAction(accessibilityNodeId, action, arguments,
2554                         interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid);
2555             } catch (RemoteException re) {
2556                 if (DEBUG) {
2557                     Slog.e(LOG_TAG, "Error calling performAccessibilityAction()");
2558                 }
2559             } finally {
2560                 Binder.restoreCallingIdentity(identityToken);
2561             }
2562             return true;
2563         }
2564 
2565         @Override
performGlobalAction(int action)2566         public boolean performGlobalAction(int action) {
2567             synchronized (mLock) {
2568                 // We treat calls from a profile as if made by its parent as profiles
2569                 // share the accessibility state of the parent. The call below
2570                 // performs the current profile parent resolution.
2571                 final int resolvedUserId = mSecurityPolicy
2572                         .resolveCallingUserIdEnforcingPermissionsLocked(
2573                                 UserHandle.USER_CURRENT);
2574                 if (resolvedUserId != mCurrentUserId) {
2575                     return false;
2576                 }
2577             }
2578             final long identity = Binder.clearCallingIdentity();
2579             try {
2580                 switch (action) {
2581                     case AccessibilityService.GLOBAL_ACTION_BACK: {
2582                         sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK);
2583                     } return true;
2584                     case AccessibilityService.GLOBAL_ACTION_HOME: {
2585                         sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME);
2586                     } return true;
2587                     case AccessibilityService.GLOBAL_ACTION_RECENTS: {
2588                         openRecents();
2589                     } return true;
2590                     case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: {
2591                         expandNotifications();
2592                     } return true;
2593                     case AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS: {
2594                         expandQuickSettings();
2595                     } return true;
2596                     case AccessibilityService.GLOBAL_ACTION_POWER_DIALOG: {
2597                         showGlobalActions();
2598                     } return true;
2599                 }
2600                 return false;
2601             } finally {
2602                 Binder.restoreCallingIdentity(identity);
2603             }
2604         }
2605 
2606         @Override
dump(FileDescriptor fd, final PrintWriter pw, String[] args)2607         public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
2608             mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
2609             synchronized (mLock) {
2610                 pw.append("Service[label=" + mAccessibilityServiceInfo.getResolveInfo()
2611                         .loadLabel(mContext.getPackageManager()));
2612                 pw.append(", feedbackType"
2613                         + AccessibilityServiceInfo.feedbackTypeToString(mFeedbackType));
2614                 pw.append(", capabilities=" + mAccessibilityServiceInfo.getCapabilities());
2615                 pw.append(", eventTypes="
2616                         + AccessibilityEvent.eventTypeToString(mEventTypes));
2617                 pw.append(", notificationTimeout=" + mNotificationTimeout);
2618                 pw.append("]");
2619             }
2620         }
2621 
2622         @Override
onServiceDisconnected(ComponentName componentName)2623         public void onServiceDisconnected(ComponentName componentName) {
2624             /* do nothing - #binderDied takes care */
2625         }
2626 
onAdded()2627         public void onAdded() throws RemoteException {
2628             linkToOwnDeathLocked();
2629             final long identity = Binder.clearCallingIdentity();
2630             try {
2631                 mWindowManagerService.addWindowToken(mOverlayWindowToken,
2632                         WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY);
2633             } finally {
2634                 Binder.restoreCallingIdentity(identity);
2635             }
2636         }
2637 
onRemoved()2638         public void onRemoved() {
2639             final long identity = Binder.clearCallingIdentity();
2640             try {
2641                 mWindowManagerService.removeWindowToken(mOverlayWindowToken, true);
2642             } finally {
2643                 Binder.restoreCallingIdentity(identity);
2644             }
2645             unlinkToOwnDeathLocked();
2646         }
2647 
linkToOwnDeathLocked()2648         public void linkToOwnDeathLocked() throws RemoteException {
2649             mService.linkToDeath(this, 0);
2650         }
2651 
unlinkToOwnDeathLocked()2652         public void unlinkToOwnDeathLocked() {
2653             mService.unlinkToDeath(this, 0);
2654         }
2655 
resetLocked()2656         public void resetLocked() {
2657             try {
2658                 // Clear the proxy in the other process so this
2659                 // IAccessibilityServiceConnection can be garbage collected.
2660                 mServiceInterface.init(null, mId, null);
2661             } catch (RemoteException re) {
2662                 /* ignore */
2663             }
2664             mService = null;
2665             mServiceInterface = null;
2666         }
2667 
isConnectedLocked()2668         public boolean isConnectedLocked() {
2669             return (mService != null);
2670         }
2671 
binderDied()2672         public void binderDied() {
2673             synchronized (mLock) {
2674                 // It is possible that this service's package was force stopped during
2675                 // whose handling the death recipient is unlinked and still get a call
2676                 // on binderDied since the call was made before we unlink but was
2677                 // waiting on the lock we held during the force stop handling.
2678                 if (!isConnectedLocked()) {
2679                     return;
2680                 }
2681                 mWasConnectedAndDied = true;
2682                 mKeyEventDispatcher.flush();
2683                 UserState userState = getUserStateLocked(mUserId);
2684                 // The death recipient is unregistered in removeServiceLocked
2685                 removeServiceLocked(this, userState);
2686                 resetLocked();
2687                 if (mIsAutomation) {
2688                     // We no longer have an automation service, so restore
2689                     // the state based on values in the settings database.
2690                     userState.mInstalledServices.remove(mAccessibilityServiceInfo);
2691                     userState.mEnabledServices.remove(mComponentName);
2692                     userState.destroyUiAutomationService();
2693                     if (readConfigurationForUserStateLocked(userState)) {
2694                         onUserStateChangedLocked(userState);
2695                     }
2696                 }
2697             }
2698         }
2699 
2700         /**
2701          * Performs a notification for an {@link AccessibilityEvent}.
2702          *
2703          * @param event The event.
2704          */
notifyAccessibilityEvent(AccessibilityEvent event)2705         public void notifyAccessibilityEvent(AccessibilityEvent event) {
2706             synchronized (mLock) {
2707                 final int eventType = event.getEventType();
2708                 // Make a copy since during dispatch it is possible the event to
2709                 // be modified to remove its source if the receiving service does
2710                 // not have permission to access the window content.
2711                 AccessibilityEvent newEvent = AccessibilityEvent.obtain(event);
2712                 AccessibilityEvent oldEvent = mPendingEvents.get(eventType);
2713                 mPendingEvents.put(eventType, newEvent);
2714 
2715                 final int what = eventType;
2716                 if (oldEvent != null) {
2717                     mEventDispatchHandler.removeMessages(what);
2718                     oldEvent.recycle();
2719                 }
2720 
2721                 Message message = mEventDispatchHandler.obtainMessage(what);
2722                 mEventDispatchHandler.sendMessageDelayed(message, mNotificationTimeout);
2723             }
2724         }
2725 
2726         /**
2727          * Notifies an accessibility service client for a scheduled event given the event type.
2728          *
2729          * @param eventType The type of the event to dispatch.
2730          */
notifyAccessibilityEventInternal(int eventType)2731         private void notifyAccessibilityEventInternal(int eventType) {
2732             IAccessibilityServiceClient listener;
2733             AccessibilityEvent event;
2734 
2735             synchronized (mLock) {
2736                 listener = mServiceInterface;
2737 
2738                 // If the service died/was disabled while the message for dispatching
2739                 // the accessibility event was propagating the listener may be null.
2740                 if (listener == null) {
2741                     return;
2742                 }
2743 
2744                 event = mPendingEvents.get(eventType);
2745 
2746                 // Check for null here because there is a concurrent scenario in which this
2747                 // happens: 1) A binder thread calls notifyAccessibilityServiceDelayedLocked
2748                 // which posts a message for dispatching an event. 2) The message is pulled
2749                 // from the queue by the handler on the service thread and the latter is
2750                 // just about to acquire the lock and call this method. 3) Now another binder
2751                 // thread acquires the lock calling notifyAccessibilityServiceDelayedLocked
2752                 // so the service thread waits for the lock; 4) The binder thread replaces
2753                 // the event with a more recent one (assume the same event type) and posts a
2754                 // dispatch request releasing the lock. 5) Now the main thread is unblocked and
2755                 // dispatches the event which is removed from the pending ones. 6) And ... now
2756                 // the service thread handles the last message posted by the last binder call
2757                 // but the event is already dispatched and hence looking it up in the pending
2758                 // ones yields null. This check is much simpler that keeping count for each
2759                 // event type of each service to catch such a scenario since only one message
2760                 // is processed at a time.
2761                 if (event == null) {
2762                     return;
2763                 }
2764 
2765                 mPendingEvents.remove(eventType);
2766                 if (mSecurityPolicy.canRetrieveWindowContentLocked(this)) {
2767                     event.setConnectionId(mId);
2768                 } else {
2769                     event.setSource(null);
2770                 }
2771                 event.setSealed(true);
2772             }
2773 
2774             try {
2775                 listener.onAccessibilityEvent(event);
2776                 if (DEBUG) {
2777                     Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
2778                 }
2779             } catch (RemoteException re) {
2780                 Slog.e(LOG_TAG, "Error during sending " + event + " to " + listener, re);
2781             } finally {
2782                 event.recycle();
2783             }
2784         }
2785 
notifyGesture(int gestureId)2786         public void notifyGesture(int gestureId) {
2787             mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_GESTURE,
2788                     gestureId, 0).sendToTarget();
2789         }
2790 
notifyKeyEvent(KeyEvent event, int policyFlags)2791         public void notifyKeyEvent(KeyEvent event, int policyFlags) {
2792             mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_KEY_EVENT,
2793                     policyFlags, 0, event).sendToTarget();
2794         }
2795 
notifyClearAccessibilityNodeInfoCache()2796         public void notifyClearAccessibilityNodeInfoCache() {
2797             mInvocationHandler.sendEmptyMessage(
2798                     InvocationHandler.MSG_CLEAR_ACCESSIBILITY_CACHE);
2799         }
2800 
notifyGestureInternal(int gestureId)2801         private void notifyGestureInternal(int gestureId) {
2802             final IAccessibilityServiceClient listener;
2803             synchronized (mLock) {
2804                 listener = mServiceInterface;
2805             }
2806             if (listener != null) {
2807                 try {
2808                     listener.onGesture(gestureId);
2809                 } catch (RemoteException re) {
2810                     Slog.e(LOG_TAG, "Error during sending gesture " + gestureId
2811                             + " to " + mService, re);
2812                 }
2813             }
2814         }
2815 
notifyKeyEventInternal(KeyEvent event, int policyFlags)2816         private void notifyKeyEventInternal(KeyEvent event, int policyFlags) {
2817             mKeyEventDispatcher.notifyKeyEvent(event, policyFlags);
2818         }
2819 
notifyClearAccessibilityCacheInternal()2820         private void notifyClearAccessibilityCacheInternal() {
2821             final IAccessibilityServiceClient listener;
2822             synchronized (mLock) {
2823                 listener = mServiceInterface;
2824             }
2825             if (listener != null) {
2826                 try {
2827                     listener.clearAccessibilityCache();
2828                 } catch (RemoteException re) {
2829                     Slog.e(LOG_TAG, "Error during requesting accessibility info cache"
2830                             + " to be cleared.", re);
2831                 }
2832             }
2833         }
2834 
sendDownAndUpKeyEvents(int keyCode)2835         private void sendDownAndUpKeyEvents(int keyCode) {
2836             final long token = Binder.clearCallingIdentity();
2837 
2838             // Inject down.
2839             final long downTime = SystemClock.uptimeMillis();
2840             KeyEvent down = KeyEvent.obtain(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
2841                     KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM,
2842                     InputDevice.SOURCE_KEYBOARD, null);
2843             InputManager.getInstance().injectInputEvent(down,
2844                     InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
2845             down.recycle();
2846 
2847             // Inject up.
2848             final long upTime = SystemClock.uptimeMillis();
2849             KeyEvent up = KeyEvent.obtain(downTime, upTime, KeyEvent.ACTION_UP, keyCode, 0, 0,
2850                     KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM,
2851                     InputDevice.SOURCE_KEYBOARD, null);
2852             InputManager.getInstance().injectInputEvent(up,
2853                     InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
2854             up.recycle();
2855 
2856             Binder.restoreCallingIdentity(token);
2857         }
2858 
expandNotifications()2859         private void expandNotifications() {
2860             final long token = Binder.clearCallingIdentity();
2861 
2862             StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService(
2863                     android.app.Service.STATUS_BAR_SERVICE);
2864             statusBarManager.expandNotificationsPanel();
2865 
2866             Binder.restoreCallingIdentity(token);
2867         }
2868 
expandQuickSettings()2869         private void expandQuickSettings() {
2870             final long token = Binder.clearCallingIdentity();
2871 
2872             StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService(
2873                     android.app.Service.STATUS_BAR_SERVICE);
2874             statusBarManager.expandSettingsPanel();
2875 
2876             Binder.restoreCallingIdentity(token);
2877         }
2878 
openRecents()2879         private void openRecents() {
2880             final long token = Binder.clearCallingIdentity();
2881 
2882             IStatusBarService statusBarService = IStatusBarService.Stub.asInterface(
2883                     ServiceManager.getService("statusbar"));
2884             try {
2885                 statusBarService.toggleRecentApps();
2886             } catch (RemoteException e) {
2887                 Slog.e(LOG_TAG, "Error toggling recent apps.");
2888             }
2889 
2890             Binder.restoreCallingIdentity(token);
2891         }
2892 
showGlobalActions()2893         private void showGlobalActions() {
2894             mWindowManagerService.showGlobalActions();
2895         }
2896 
getConnectionLocked(int windowId)2897         private IAccessibilityInteractionConnection getConnectionLocked(int windowId) {
2898             if (DEBUG) {
2899                 Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
2900             }
2901             AccessibilityConnectionWrapper wrapper = mGlobalInteractionConnections.get(windowId);
2902             if (wrapper == null) {
2903                 wrapper = getCurrentUserStateLocked().mInteractionConnections.get(windowId);
2904             }
2905             if (wrapper != null && wrapper.mConnection != null) {
2906                 return wrapper.mConnection;
2907             }
2908             if (DEBUG) {
2909                 Slog.e(LOG_TAG, "No interaction connection to window: " + windowId);
2910             }
2911             return null;
2912         }
2913 
resolveAccessibilityWindowIdLocked(int accessibilityWindowId)2914         private int resolveAccessibilityWindowIdLocked(int accessibilityWindowId) {
2915             if (accessibilityWindowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) {
2916                 return mSecurityPolicy.getActiveWindowId();
2917             }
2918             return accessibilityWindowId;
2919         }
2920 
resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType)2921         private int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) {
2922             if (windowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) {
2923                 return mSecurityPolicy.mActiveWindowId;
2924             }
2925             if (windowId == AccessibilityNodeInfo.ANY_WINDOW_ID) {
2926                 if (focusType == AccessibilityNodeInfo.FOCUS_INPUT) {
2927                     return mSecurityPolicy.mFocusedWindowId;
2928                 } else if (focusType == AccessibilityNodeInfo.FOCUS_ACCESSIBILITY) {
2929                     return mSecurityPolicy.mAccessibilityFocusedWindowId;
2930                 }
2931             }
2932             return windowId;
2933         }
2934 
2935         private final class InvocationHandler extends Handler {
2936             public static final int MSG_ON_GESTURE = 1;
2937             public static final int MSG_ON_KEY_EVENT = 2;
2938             public static final int MSG_CLEAR_ACCESSIBILITY_CACHE = 3;
2939             public static final int MSG_ON_KEY_EVENT_TIMEOUT = 4;
2940 
InvocationHandler(Looper looper)2941             public InvocationHandler(Looper looper) {
2942                 super(looper, null, true);
2943             }
2944 
2945             @Override
handleMessage(Message message)2946             public void handleMessage(Message message) {
2947                 final int type = message.what;
2948                 switch (type) {
2949                     case MSG_ON_GESTURE: {
2950                         final int gestureId = message.arg1;
2951                         notifyGestureInternal(gestureId);
2952                     } break;
2953 
2954                     case MSG_ON_KEY_EVENT: {
2955                         KeyEvent event = (KeyEvent) message.obj;
2956                         final int policyFlags = message.arg1;
2957                         notifyKeyEventInternal(event, policyFlags);
2958                     } break;
2959 
2960                     case MSG_CLEAR_ACCESSIBILITY_CACHE: {
2961                         notifyClearAccessibilityCacheInternal();
2962                     } break;
2963 
2964                     case MSG_ON_KEY_EVENT_TIMEOUT: {
2965                         PendingEvent eventState = (PendingEvent) message.obj;
2966                         setOnKeyEventResult(false, eventState.sequence);
2967                     } break;
2968 
2969                     default: {
2970                         throw new IllegalArgumentException("Unknown message: " + type);
2971                     }
2972                 }
2973             }
2974         }
2975 
2976         private final class KeyEventDispatcher {
2977 
2978             private static final long ON_KEY_EVENT_TIMEOUT_MILLIS = 500;
2979 
2980             private PendingEvent mPendingEvents;
2981 
2982             private final InputEventConsistencyVerifier mSentEventsVerifier =
2983                     InputEventConsistencyVerifier.isInstrumentationEnabled()
2984                             ? new InputEventConsistencyVerifier(
2985                                     this, 0, KeyEventDispatcher.class.getSimpleName()) : null;
2986 
notifyKeyEvent(KeyEvent event, int policyFlags)2987             public void notifyKeyEvent(KeyEvent event, int policyFlags) {
2988                 final PendingEvent pendingEvent;
2989 
2990                 synchronized (mLock) {
2991                     pendingEvent = addPendingEventLocked(event, policyFlags);
2992                 }
2993 
2994                 Message message = mInvocationHandler.obtainMessage(
2995                         InvocationHandler.MSG_ON_KEY_EVENT_TIMEOUT, pendingEvent);
2996                 mInvocationHandler.sendMessageDelayed(message, ON_KEY_EVENT_TIMEOUT_MILLIS);
2997 
2998                 try {
2999                     // Accessibility services are exclusively not in the system
3000                     // process, therefore no need to clone the motion event to
3001                     // prevent tampering. It will be cloned in the IPC call.
3002                     mServiceInterface.onKeyEvent(pendingEvent.event, pendingEvent.sequence);
3003                 } catch (RemoteException re) {
3004                     setOnKeyEventResult(false, pendingEvent.sequence);
3005                 }
3006             }
3007 
setOnKeyEventResult(boolean handled, int sequence)3008             public void setOnKeyEventResult(boolean handled, int sequence) {
3009                 synchronized (mLock) {
3010                     PendingEvent pendingEvent = removePendingEventLocked(sequence);
3011                     if (pendingEvent != null) {
3012                         mInvocationHandler.removeMessages(
3013                                 InvocationHandler.MSG_ON_KEY_EVENT_TIMEOUT,
3014                                 pendingEvent);
3015                         pendingEvent.handled = handled;
3016                         finishPendingEventLocked(pendingEvent);
3017                     }
3018                 }
3019             }
3020 
flush()3021             public void flush() {
3022                 synchronized (mLock) {
3023                     cancelAllPendingEventsLocked();
3024                     if (mSentEventsVerifier != null) {
3025                         mSentEventsVerifier.reset();
3026                     }
3027                 }
3028             }
3029 
addPendingEventLocked(KeyEvent event, int policyFlags)3030             private PendingEvent addPendingEventLocked(KeyEvent event, int policyFlags) {
3031                 final int sequence = event.getSequenceNumber();
3032                 PendingEvent pendingEvent = obtainPendingEventLocked(event, policyFlags, sequence);
3033                 pendingEvent.next = mPendingEvents;
3034                 mPendingEvents = pendingEvent;
3035                 return pendingEvent;
3036             }
3037 
removePendingEventLocked(int sequence)3038             private PendingEvent removePendingEventLocked(int sequence) {
3039                 PendingEvent previous = null;
3040                 PendingEvent current = mPendingEvents;
3041 
3042                 while (current != null) {
3043                     if (current.sequence == sequence) {
3044                         if (previous != null) {
3045                             previous.next = current.next;
3046                         } else {
3047                             mPendingEvents = current.next;
3048                         }
3049                         current.next = null;
3050                         return current;
3051                     }
3052                     previous = current;
3053                     current = current.next;
3054                 }
3055                 return null;
3056             }
3057 
finishPendingEventLocked(PendingEvent pendingEvent)3058             private void finishPendingEventLocked(PendingEvent pendingEvent) {
3059                 if (!pendingEvent.handled) {
3060                     sendKeyEventToInputFilter(pendingEvent.event, pendingEvent.policyFlags);
3061                 }
3062                 // Nullify the event since we do not want it to be
3063                 // recycled yet. It will be sent to the input filter.
3064                 pendingEvent.event = null;
3065                 recyclePendingEventLocked(pendingEvent);
3066             }
3067 
sendKeyEventToInputFilter(KeyEvent event, int policyFlags)3068             private void sendKeyEventToInputFilter(KeyEvent event, int policyFlags) {
3069                 if (DEBUG) {
3070                     Slog.i(LOG_TAG, "Injecting event: " + event);
3071                 }
3072                 if (mSentEventsVerifier != null) {
3073                     mSentEventsVerifier.onKeyEvent(event, 0);
3074                 }
3075                 policyFlags |= WindowManagerPolicy.FLAG_PASS_TO_USER;
3076                 mMainHandler.obtainMessage(MainHandler.MSG_SEND_KEY_EVENT_TO_INPUT_FILTER,
3077                         policyFlags, 0, event).sendToTarget();
3078             }
3079 
cancelAllPendingEventsLocked()3080             private void cancelAllPendingEventsLocked() {
3081                 while (mPendingEvents != null) {
3082                     PendingEvent pendingEvent = removePendingEventLocked(mPendingEvents.sequence);
3083                     pendingEvent.handled = false;
3084                     mInvocationHandler.removeMessages(InvocationHandler.MSG_ON_KEY_EVENT_TIMEOUT,
3085                             pendingEvent);
3086                     finishPendingEventLocked(pendingEvent);
3087                 }
3088             }
3089         }
3090     }
3091 
3092     private static final class PendingEvent {
3093         PendingEvent next;
3094 
3095         KeyEvent event;
3096         int policyFlags;
3097         int sequence;
3098         boolean handled;
3099 
clear()3100         public void clear() {
3101             if (event != null) {
3102                 event.recycle();
3103                 event = null;
3104             }
3105             next = null;
3106             policyFlags = 0;
3107             sequence = 0;
3108             handled = false;
3109         }
3110     }
3111 
3112     final class WindowsForAccessibilityCallback implements
3113             WindowManagerInternal.WindowsForAccessibilityCallback {
3114 
3115         @Override
onWindowsForAccessibilityChanged(List<WindowInfo> windows)3116         public void onWindowsForAccessibilityChanged(List<WindowInfo> windows) {
3117             synchronized (mLock) {
3118                 // Populate the windows to report.
3119                 List<AccessibilityWindowInfo> reportedWindows = new ArrayList<>();
3120                 final int receivedWindowCount = windows.size();
3121                 for (int i = 0; i < receivedWindowCount; i++) {
3122                     WindowInfo receivedWindow = windows.get(i);
3123                     AccessibilityWindowInfo reportedWindow = populateReportedWindow(
3124                             receivedWindow);
3125                     if (reportedWindow != null) {
3126                         reportedWindows.add(reportedWindow);
3127                     }
3128                 }
3129 
3130                 if (DEBUG) {
3131                     Slog.i(LOG_TAG, "Windows changed: " + reportedWindows);
3132                 }
3133 
3134                 // Let the policy update the focused and active windows.
3135                 mSecurityPolicy.updateWindowsLocked(reportedWindows);
3136 
3137                 // Someone may be waiting for the windows - advertise it.
3138                 mLock.notifyAll();
3139             }
3140         }
3141 
populateReportedWindow(WindowInfo window)3142         private AccessibilityWindowInfo populateReportedWindow(WindowInfo window) {
3143             final int windowId = findWindowIdLocked(window.token);
3144             if (windowId < 0) {
3145                 return null;
3146             }
3147 
3148             AccessibilityWindowInfo reportedWindow = AccessibilityWindowInfo.obtain();
3149 
3150             reportedWindow.setId(windowId);
3151             reportedWindow.setType(getTypeForWindowManagerWindowType(window.type));
3152             reportedWindow.setLayer(window.layer);
3153             reportedWindow.setFocused(window.focused);
3154             reportedWindow.setBoundsInScreen(window.boundsInScreen);
3155 
3156             final int parentId = findWindowIdLocked(window.parentToken);
3157             if (parentId >= 0) {
3158                 reportedWindow.setParentId(parentId);
3159             }
3160 
3161             if (window.childTokens != null) {
3162                 final int childCount = window.childTokens.size();
3163                 for (int i = 0; i < childCount; i++) {
3164                     IBinder childToken = window.childTokens.get(i);
3165                     final int childId = findWindowIdLocked(childToken);
3166                     if (childId >= 0) {
3167                         reportedWindow.addChild(childId);
3168                     }
3169                 }
3170             }
3171 
3172             return reportedWindow;
3173         }
3174 
getTypeForWindowManagerWindowType(int windowType)3175         private int getTypeForWindowManagerWindowType(int windowType) {
3176             switch (windowType) {
3177                 case WindowManager.LayoutParams.TYPE_APPLICATION:
3178                 case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
3179                 case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
3180                 case WindowManager.LayoutParams.TYPE_APPLICATION_STARTING:
3181                 case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
3182                 case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL:
3183                 case WindowManager.LayoutParams.TYPE_BASE_APPLICATION:
3184                 case WindowManager.LayoutParams.TYPE_PHONE:
3185                 case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
3186                 case WindowManager.LayoutParams.TYPE_TOAST:
3187                 case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG: {
3188                     return AccessibilityWindowInfo.TYPE_APPLICATION;
3189                 }
3190 
3191                 case WindowManager.LayoutParams.TYPE_INPUT_METHOD:
3192                 case WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG: {
3193                     return AccessibilityWindowInfo.TYPE_INPUT_METHOD;
3194                 }
3195 
3196                 case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
3197                 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR:
3198                 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL:
3199                 case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
3200                 case WindowManager.LayoutParams.TYPE_STATUS_BAR:
3201                 case WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL:
3202                 case WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL:
3203                 case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
3204                 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
3205                 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
3206                 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
3207                 case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: {
3208                     return AccessibilityWindowInfo.TYPE_SYSTEM;
3209                 }
3210 
3211                 case WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY: {
3212                     return AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY;
3213                 }
3214 
3215                 default: {
3216                     return -1;
3217                 }
3218             }
3219         }
3220     }
3221 
3222     private final class InteractionBridge {
3223         private final Display mDefaultDisplay;
3224         private final int mConnectionId;
3225         private final AccessibilityInteractionClient mClient;
3226 
InteractionBridge()3227         public InteractionBridge() {
3228             AccessibilityServiceInfo info = new AccessibilityServiceInfo();
3229             info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
3230             info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
3231             info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
3232             Service service = new Service(UserHandle.USER_NULL,
3233                     sFakeAccessibilityServiceComponentName, info);
3234 
3235             mConnectionId = service.mId;
3236 
3237             mClient = AccessibilityInteractionClient.getInstance();
3238             mClient.addConnection(mConnectionId, service);
3239 
3240             //TODO: (multi-display) We need to support multiple displays.
3241             DisplayManager displayManager = (DisplayManager)
3242                     mContext.getSystemService(Context.DISPLAY_SERVICE);
3243             mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
3244         }
3245 
clearAccessibilityFocusNotLocked(int windowId)3246         public void clearAccessibilityFocusNotLocked(int windowId) {
3247             AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked(windowId);
3248             if (focus != null) {
3249                 focus.performAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
3250             }
3251         }
3252 
getAccessibilityFocusClickPointInScreenNotLocked(Point outPoint)3253         public boolean getAccessibilityFocusClickPointInScreenNotLocked(Point outPoint) {
3254             AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked();
3255             if (focus == null) {
3256                 return false;
3257             }
3258 
3259             synchronized (mLock) {
3260                 Rect boundsInScreen = mTempRect;
3261                 focus.getBoundsInScreen(boundsInScreen);
3262 
3263                 // Clip to the window bounds.
3264                 Rect windowBounds = mTempRect1;
3265                 getWindowBounds(focus.getWindowId(), windowBounds);
3266                 if (!boundsInScreen.intersect(windowBounds)) {
3267                     return false;
3268                 }
3269 
3270                 // Apply magnification if needed.
3271                 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId());
3272                 if (spec != null && !spec.isNop()) {
3273                     boundsInScreen.offset((int) -spec.offsetX, (int) -spec.offsetY);
3274                     boundsInScreen.scale(1 / spec.scale);
3275                 }
3276 
3277                 // Clip to the screen bounds.
3278                 Point screenSize = mTempPoint;
3279                 mDefaultDisplay.getRealSize(screenSize);
3280                 if (!boundsInScreen.intersect(0, 0, screenSize.x, screenSize.y)) {
3281                     return false;
3282                 }
3283 
3284                 outPoint.set(boundsInScreen.centerX(), boundsInScreen.centerY());
3285             }
3286 
3287             return true;
3288         }
3289 
getAccessibilityFocusNotLocked()3290         private AccessibilityNodeInfo getAccessibilityFocusNotLocked() {
3291             final int focusedWindowId;
3292             synchronized (mLock) {
3293                 focusedWindowId = mSecurityPolicy.mAccessibilityFocusedWindowId;
3294                 if (focusedWindowId == SecurityPolicy.INVALID_WINDOW_ID) {
3295                     return null;
3296                 }
3297             }
3298             return getAccessibilityFocusNotLocked(focusedWindowId);
3299         }
3300 
getAccessibilityFocusNotLocked(int windowId)3301         private AccessibilityNodeInfo getAccessibilityFocusNotLocked(int windowId) {
3302             return mClient.findFocus(mConnectionId,
3303                     windowId, AccessibilityNodeInfo.ROOT_NODE_ID,
3304                     AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
3305         }
3306     }
3307 
3308     final class SecurityPolicy {
3309         public static final int INVALID_WINDOW_ID = -1;
3310 
3311         private static final int RETRIEVAL_ALLOWING_EVENT_TYPES =
3312             AccessibilityEvent.TYPE_VIEW_CLICKED
3313             | AccessibilityEvent.TYPE_VIEW_FOCUSED
3314             | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
3315             | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
3316             | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED
3317             | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
3318             | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
3319             | AccessibilityEvent.TYPE_VIEW_SELECTED
3320             | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
3321             | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED
3322             | AccessibilityEvent.TYPE_VIEW_SCROLLED
3323             | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
3324             | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED
3325             | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY;
3326 
3327         public List<AccessibilityWindowInfo> mWindows;
3328 
3329         public int mActiveWindowId = INVALID_WINDOW_ID;
3330         public int mFocusedWindowId = INVALID_WINDOW_ID;
3331         public int mAccessibilityFocusedWindowId = INVALID_WINDOW_ID;
3332         public long mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
3333 
3334         private boolean mTouchInteractionInProgress;
3335 
canDispatchAccessibilityEventLocked(AccessibilityEvent event)3336         private boolean canDispatchAccessibilityEventLocked(AccessibilityEvent event) {
3337             final int eventType = event.getEventType();
3338             switch (eventType) {
3339                 // All events that are for changes in a global window
3340                 // state should *always* be dispatched.
3341                 case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
3342                 case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
3343                 case AccessibilityEvent.TYPE_ANNOUNCEMENT:
3344                 // All events generated by the user touching the
3345                 // screen should *always* be dispatched.
3346                 case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START:
3347                 case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END:
3348                 case AccessibilityEvent.TYPE_GESTURE_DETECTION_START:
3349                 case AccessibilityEvent.TYPE_GESTURE_DETECTION_END:
3350                 case AccessibilityEvent.TYPE_TOUCH_INTERACTION_START:
3351                 case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END:
3352                 case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
3353                 case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT:
3354                 // Also always dispatch the event that assist is reading context.
3355                 case AccessibilityEvent.TYPE_ASSIST_READING_CONTEXT:
3356                 // Also windows changing should always be anounced.
3357                 case AccessibilityEvent.TYPE_WINDOWS_CHANGED: {
3358                     return true;
3359                 }
3360                 // All events for changes in window content should be
3361                 // dispatched *only* if this window is one of the windows
3362                 // the accessibility layer reports which are windows
3363                 // that a sighted user can touch.
3364                 default: {
3365                     return isRetrievalAllowingWindow(event.getWindowId());
3366                 }
3367             }
3368         }
3369 
clearWindowsLocked()3370         public void clearWindowsLocked() {
3371             List<AccessibilityWindowInfo> windows = Collections.emptyList();
3372             final int activeWindowId = mActiveWindowId;
3373             updateWindowsLocked(windows);
3374             mActiveWindowId = activeWindowId;
3375             mWindows = null;
3376         }
3377 
updateWindowsLocked(List<AccessibilityWindowInfo> windows)3378         public void updateWindowsLocked(List<AccessibilityWindowInfo> windows) {
3379             if (mWindows == null) {
3380                 mWindows = new ArrayList<>();
3381             }
3382 
3383             final int oldWindowCount = mWindows.size();
3384             for (int i = oldWindowCount - 1; i >= 0; i--) {
3385                 mWindows.remove(i).recycle();
3386             }
3387 
3388             mFocusedWindowId = INVALID_WINDOW_ID;
3389             if (!mTouchInteractionInProgress) {
3390                 mActiveWindowId = INVALID_WINDOW_ID;
3391             }
3392 
3393             // If the active window goes away while the user is touch exploring we
3394             // reset the active window id and wait for the next hover event from
3395             // under the user's finger to determine which one is the new one. It
3396             // is possible that the finger is not moving and the input system
3397             // filters out such events.
3398             boolean activeWindowGone = true;
3399 
3400             final int windowCount = windows.size();
3401             if (windowCount > 0) {
3402                 for (int i = 0; i < windowCount; i++) {
3403                     AccessibilityWindowInfo window = windows.get(i);
3404                     final int windowId = window.getId();
3405                     if (window.isFocused()) {
3406                         mFocusedWindowId = windowId;
3407                         if (!mTouchInteractionInProgress) {
3408                             mActiveWindowId = windowId;
3409                             window.setActive(true);
3410                         } else if (windowId == mActiveWindowId) {
3411                             activeWindowGone = false;
3412                         }
3413                     }
3414                     mWindows.add(window);
3415                 }
3416 
3417                 if (mTouchInteractionInProgress && activeWindowGone) {
3418                     mActiveWindowId = mFocusedWindowId;
3419                 }
3420 
3421                 // Focused window may change the active one, so set the
3422                 // active window once we decided which it is.
3423                 for (int i = 0; i < windowCount; i++) {
3424                     AccessibilityWindowInfo window = mWindows.get(i);
3425                     if (window.getId() == mActiveWindowId) {
3426                         window.setActive(true);
3427                     }
3428                     if (window.getId() == mAccessibilityFocusedWindowId) {
3429                         window.setAccessibilityFocused(true);
3430                     }
3431                 }
3432             }
3433 
3434             notifyWindowsChanged();
3435         }
3436 
computePartialInteractiveRegionForWindowLocked(int windowId, Region outRegion)3437         public boolean computePartialInteractiveRegionForWindowLocked(int windowId,
3438                 Region outRegion) {
3439             if (mWindows == null) {
3440                 return false;
3441             }
3442 
3443             // Windows are ordered in z order so start from the bottom and find
3444             // the window of interest. After that all windows that cover it should
3445             // be subtracted from the resulting region. Note that for accessibility
3446             // we are returning only interactive windows.
3447             Region windowInteractiveRegion = null;
3448             boolean windowInteractiveRegionChanged = false;
3449 
3450             final int windowCount = mWindows.size();
3451             for (int i = windowCount - 1; i >= 0; i--) {
3452                 AccessibilityWindowInfo currentWindow = mWindows.get(i);
3453                 if (windowInteractiveRegion == null) {
3454                     if (currentWindow.getId() == windowId) {
3455                         Rect currentWindowBounds = mTempRect;
3456                         currentWindow.getBoundsInScreen(currentWindowBounds);
3457                         outRegion.set(currentWindowBounds);
3458                         windowInteractiveRegion = outRegion;
3459                         continue;
3460                     }
3461                 } else if (currentWindow.getType()
3462                         != AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY) {
3463                     Rect currentWindowBounds = mTempRect;
3464                     currentWindow.getBoundsInScreen(currentWindowBounds);
3465                     if (windowInteractiveRegion.op(currentWindowBounds, Region.Op.DIFFERENCE)) {
3466                         windowInteractiveRegionChanged = true;
3467                     }
3468                 }
3469             }
3470 
3471             return windowInteractiveRegionChanged;
3472         }
3473 
updateEventSourceLocked(AccessibilityEvent event)3474         public void updateEventSourceLocked(AccessibilityEvent event) {
3475             if ((event.getEventType() & RETRIEVAL_ALLOWING_EVENT_TYPES) == 0) {
3476                 event.setSource(null);
3477             }
3478         }
3479 
updateActiveAndAccessibilityFocusedWindowLocked(int windowId, long nodeId, int eventType)3480         public void updateActiveAndAccessibilityFocusedWindowLocked(int windowId, long nodeId,
3481                 int eventType) {
3482             // The active window is either the window that has input focus or
3483             // the window that the user is currently touching. If the user is
3484             // touching a window that does not have input focus as soon as the
3485             // the user stops touching that window the focused window becomes
3486             // the active one. Here we detect the touched window and make it
3487             // active. In updateWindowsLocked() we update the focused window
3488             // and if the user is not touching the screen, we make the focused
3489             // window the active one.
3490             switch (eventType) {
3491                 case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: {
3492                     // If no service has the capability to introspect screen,
3493                     // we do not register callback in the window manager for
3494                     // window changes, so we have to ask the window manager
3495                     // what the focused window is to update the active one.
3496                     // The active window also determined events from which
3497                     // windows are delivered.
3498                     synchronized (mLock) {
3499                         if (mWindowsForAccessibilityCallback == null) {
3500                             mFocusedWindowId = getFocusedWindowId();
3501                             if (windowId == mFocusedWindowId) {
3502                                 mActiveWindowId = windowId;
3503                             }
3504                         }
3505                     }
3506                 } break;
3507 
3508                 case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER: {
3509                     // Do not allow delayed hover events to confuse us
3510                     // which the active window is.
3511                     synchronized (mLock) {
3512                         if (mTouchInteractionInProgress && mActiveWindowId != windowId) {
3513                             setActiveWindowLocked(windowId);
3514                         }
3515                     }
3516                 } break;
3517 
3518                 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
3519                     synchronized (mLock) {
3520                         if (mAccessibilityFocusedWindowId != windowId) {
3521                             mMainHandler.obtainMessage(MainHandler.MSG_CLEAR_ACCESSIBILITY_FOCUS,
3522                                     mAccessibilityFocusedWindowId, 0).sendToTarget();
3523                             mSecurityPolicy.setAccessibilityFocusedWindowLocked(windowId);
3524                             mAccessibilityFocusNodeId = nodeId;
3525                         }
3526                     }
3527                 } break;
3528 
3529                 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
3530                     synchronized (mLock) {
3531                         if (mAccessibilityFocusNodeId == nodeId) {
3532                             mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
3533                         }
3534                         if (mAccessibilityFocusNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID
3535                                 && mAccessibilityFocusedWindowId == windowId) {
3536                             mAccessibilityFocusedWindowId = INVALID_WINDOW_ID;
3537                         }
3538                     }
3539                 } break;
3540             }
3541         }
3542 
onTouchInteractionStart()3543         public void onTouchInteractionStart() {
3544             synchronized (mLock) {
3545                 mTouchInteractionInProgress = true;
3546             }
3547         }
3548 
onTouchInteractionEnd()3549         public void onTouchInteractionEnd() {
3550             synchronized (mLock) {
3551                 mTouchInteractionInProgress = false;
3552                 // We want to set the active window to be current immediately
3553                 // after the user has stopped touching the screen since if the
3554                 // user types with the IME he should get a feedback for the
3555                 // letter typed in the text view which is in the input focused
3556                 // window. Note that we always deliver hover accessibility events
3557                 // (they are a result of user touching the screen) so change of
3558                 // the active window before all hover accessibility events from
3559                 // the touched window are delivered is fine.
3560                 final int oldActiveWindow = mSecurityPolicy.mActiveWindowId;
3561                 setActiveWindowLocked(mFocusedWindowId);
3562 
3563                 // If there is no service that can operate with active windows
3564                 // we keep accessibility focus behavior to constrain it only in
3565                 // the active window. Look at updateAccessibilityFocusBehaviorLocked
3566                 // for details.
3567                 if (oldActiveWindow != mSecurityPolicy.mActiveWindowId
3568                         && mAccessibilityFocusedWindowId == oldActiveWindow
3569                         && getCurrentUserStateLocked().mAccessibilityFocusOnlyInActiveWindow) {
3570                     mMainHandler.obtainMessage(MainHandler.MSG_CLEAR_ACCESSIBILITY_FOCUS,
3571                             oldActiveWindow, 0).sendToTarget();
3572                 }
3573             }
3574         }
3575 
getActiveWindowId()3576         public int getActiveWindowId() {
3577             if (mActiveWindowId == INVALID_WINDOW_ID && !mTouchInteractionInProgress) {
3578                 mActiveWindowId = getFocusedWindowId();
3579             }
3580             return mActiveWindowId;
3581         }
3582 
setActiveWindowLocked(int windowId)3583         private void setActiveWindowLocked(int windowId) {
3584             if (mActiveWindowId != windowId) {
3585                 mActiveWindowId = windowId;
3586                 if (mWindows != null) {
3587                     final int windowCount = mWindows.size();
3588                     for (int i = 0; i < windowCount; i++) {
3589                         AccessibilityWindowInfo window = mWindows.get(i);
3590                         window.setActive(window.getId() == windowId);
3591                     }
3592                 }
3593                 notifyWindowsChanged();
3594             }
3595         }
3596 
setAccessibilityFocusedWindowLocked(int windowId)3597         private void setAccessibilityFocusedWindowLocked(int windowId) {
3598             if (mAccessibilityFocusedWindowId != windowId) {
3599                 mAccessibilityFocusedWindowId = windowId;
3600                 if (mWindows != null) {
3601                     final int windowCount = mWindows.size();
3602                     for (int i = 0; i < windowCount; i++) {
3603                         AccessibilityWindowInfo window = mWindows.get(i);
3604                         window.setAccessibilityFocused(window.getId() == windowId);
3605                     }
3606                 }
3607 
3608                 notifyWindowsChanged();
3609             }
3610         }
3611 
notifyWindowsChanged()3612         private void notifyWindowsChanged() {
3613             if (mWindowsForAccessibilityCallback == null) {
3614                 return;
3615             }
3616             final long identity = Binder.clearCallingIdentity();
3617             try {
3618                 // Let the client know the windows changed.
3619                 AccessibilityEvent event = AccessibilityEvent.obtain(
3620                         AccessibilityEvent.TYPE_WINDOWS_CHANGED);
3621                 event.setEventTime(SystemClock.uptimeMillis());
3622                 sendAccessibilityEvent(event, mCurrentUserId);
3623             } finally {
3624                 Binder.restoreCallingIdentity(identity);
3625             }
3626         }
3627 
canGetAccessibilityNodeInfoLocked(Service service, int windowId)3628         public boolean canGetAccessibilityNodeInfoLocked(Service service, int windowId) {
3629             return canRetrieveWindowContentLocked(service) && isRetrievalAllowingWindow(windowId);
3630         }
3631 
canRetrieveWindowsLocked(Service service)3632         public boolean canRetrieveWindowsLocked(Service service) {
3633             return canRetrieveWindowContentLocked(service) && service.mRetrieveInteractiveWindows;
3634         }
3635 
canRetrieveWindowContentLocked(Service service)3636         public boolean canRetrieveWindowContentLocked(Service service) {
3637             return (service.mAccessibilityServiceInfo.getCapabilities()
3638                     & AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0;
3639         }
3640 
resolveProfileParentLocked(int userId)3641         private int resolveProfileParentLocked(int userId) {
3642             if (userId != mCurrentUserId) {
3643                 final long identity = Binder.clearCallingIdentity();
3644                 try {
3645                     UserInfo parent = mUserManager.getProfileParent(userId);
3646                     if (parent != null) {
3647                         return parent.getUserHandle().getIdentifier();
3648                     }
3649                 } finally {
3650                     Binder.restoreCallingIdentity(identity);
3651                 }
3652             }
3653             return userId;
3654         }
3655 
resolveCallingUserIdEnforcingPermissionsLocked(int userId)3656         public int resolveCallingUserIdEnforcingPermissionsLocked(int userId) {
3657             final int callingUid = Binder.getCallingUid();
3658             if (callingUid == 0
3659                     || callingUid == Process.SYSTEM_UID
3660                     || callingUid == Process.SHELL_UID) {
3661                 if (userId == UserHandle.USER_CURRENT
3662                         || userId == UserHandle.USER_CURRENT_OR_SELF) {
3663                     return mCurrentUserId;
3664                 }
3665                 return resolveProfileParentLocked(userId);
3666             }
3667             final int callingUserId = UserHandle.getUserId(callingUid);
3668             if (callingUserId == userId) {
3669                 return resolveProfileParentLocked(userId);
3670             }
3671             final int callingUserParentId = resolveProfileParentLocked(callingUserId);
3672             if (callingUserParentId == mCurrentUserId &&
3673                     (userId == UserHandle.USER_CURRENT
3674                             || userId == UserHandle.USER_CURRENT_OR_SELF)) {
3675                 return mCurrentUserId;
3676             }
3677             if (!hasPermission(Manifest.permission.INTERACT_ACROSS_USERS)
3678                     && !hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) {
3679                 throw new SecurityException("Call from user " + callingUserId + " as user "
3680                         + userId + " without permission INTERACT_ACROSS_USERS or "
3681                         + "INTERACT_ACROSS_USERS_FULL not allowed.");
3682             }
3683             if (userId == UserHandle.USER_CURRENT
3684                     || userId == UserHandle.USER_CURRENT_OR_SELF) {
3685                 return mCurrentUserId;
3686             }
3687             throw new IllegalArgumentException("Calling user can be changed to only "
3688                     + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF.");
3689         }
3690 
isCallerInteractingAcrossUsers(int userId)3691         public boolean isCallerInteractingAcrossUsers(int userId) {
3692             final int callingUid = Binder.getCallingUid();
3693             return (Binder.getCallingPid() == android.os.Process.myPid()
3694                     || callingUid == Process.SHELL_UID
3695                     || userId == UserHandle.USER_CURRENT
3696                     || userId == UserHandle.USER_CURRENT_OR_SELF);
3697         }
3698 
isRetrievalAllowingWindow(int windowId)3699         private boolean isRetrievalAllowingWindow(int windowId) {
3700             // The system gets to interact with any window it wants.
3701             if (Binder.getCallingUid() == Process.SYSTEM_UID) {
3702                 return true;
3703             }
3704             if (windowId == mActiveWindowId) {
3705                 return true;
3706             }
3707             return findWindowById(windowId) != null;
3708         }
3709 
findWindowById(int windowId)3710         private AccessibilityWindowInfo findWindowById(int windowId) {
3711             if (mWindows != null) {
3712                 final int windowCount = mWindows.size();
3713                 for (int i = 0; i < windowCount; i++) {
3714                     AccessibilityWindowInfo window = mWindows.get(i);
3715                     if (window.getId() == windowId) {
3716                         return window;
3717                     }
3718                 }
3719             }
3720             return null;
3721         }
3722 
enforceCallingPermission(String permission, String function)3723         private void enforceCallingPermission(String permission, String function) {
3724             if (OWN_PROCESS_ID == Binder.getCallingPid()) {
3725                 return;
3726             }
3727             if (!hasPermission(permission)) {
3728                 throw new SecurityException("You do not have " + permission
3729                         + " required to call " + function + " from pid="
3730                         + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
3731             }
3732         }
3733 
hasPermission(String permission)3734         private boolean hasPermission(String permission) {
3735             return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED;
3736         }
3737 
getFocusedWindowId()3738         private int getFocusedWindowId() {
3739             IBinder token = mWindowManagerService.getFocusedWindowToken();
3740             synchronized (mLock) {
3741                 return findWindowIdLocked(token);
3742             }
3743         }
3744     }
3745 
3746     private class UserState {
3747         public final int mUserId;
3748 
3749         // Non-transient state.
3750 
3751         public final RemoteCallbackList<IAccessibilityManagerClient> mClients =
3752             new RemoteCallbackList<>();
3753 
3754         public final SparseArray<AccessibilityConnectionWrapper> mInteractionConnections =
3755                 new SparseArray<>();
3756 
3757         public final SparseArray<IBinder> mWindowTokens = new SparseArray<>();
3758 
3759         // Transient state.
3760 
3761         public final CopyOnWriteArrayList<Service> mBoundServices =
3762                 new CopyOnWriteArrayList<>();
3763 
3764         public final Map<ComponentName, Service> mComponentNameToServiceMap =
3765                 new HashMap<>();
3766 
3767         public final List<AccessibilityServiceInfo> mInstalledServices =
3768                 new ArrayList<>();
3769 
3770         public final Set<ComponentName> mBindingServices = new HashSet<>();
3771 
3772         public final Set<ComponentName> mEnabledServices = new HashSet<>();
3773 
3774         public final Set<ComponentName> mTouchExplorationGrantedServices =
3775                 new HashSet<>();
3776 
3777         public int mHandledFeedbackTypes = 0;
3778 
3779         public int mLastSentClientState = -1;
3780 
3781         public boolean mIsAccessibilityEnabled;
3782         public boolean mIsTouchExplorationEnabled;
3783         public boolean mIsTextHighContrastEnabled;
3784         public boolean mIsEnhancedWebAccessibilityEnabled;
3785         public boolean mIsDisplayMagnificationEnabled;
3786         public boolean mIsFilterKeyEventsEnabled;
3787         public boolean mHasDisplayColorAdjustment;
3788         public boolean mAccessibilityFocusOnlyInActiveWindow;
3789 
3790         private Service mUiAutomationService;
3791         private IAccessibilityServiceClient mUiAutomationServiceClient;
3792 
3793         private IBinder mUiAutomationServiceOwner;
3794         private final DeathRecipient mUiAutomationSerivceOnwerDeathRecipient =
3795                 new DeathRecipient() {
3796             @Override
3797             public void binderDied() {
3798                 mUiAutomationServiceOwner.unlinkToDeath(
3799                         mUiAutomationSerivceOnwerDeathRecipient, 0);
3800                 mUiAutomationServiceOwner = null;
3801                 if (mUiAutomationService != null) {
3802                     mUiAutomationService.binderDied();
3803                 }
3804             }
3805         };
3806 
UserState(int userId)3807         public UserState(int userId) {
3808             mUserId = userId;
3809         }
3810 
getClientState()3811         public int getClientState() {
3812             int clientState = 0;
3813             if (mIsAccessibilityEnabled) {
3814                 clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
3815             }
3816             // Touch exploration relies on enabled accessibility.
3817             if (mIsAccessibilityEnabled && mIsTouchExplorationEnabled) {
3818                 clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
3819             }
3820             if (mIsTextHighContrastEnabled) {
3821                 clientState |= AccessibilityManager.STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED;
3822             }
3823             return clientState;
3824         }
3825 
onSwitchToAnotherUser()3826         public void onSwitchToAnotherUser() {
3827             // Clear UI test automation state.
3828             if (mUiAutomationService != null) {
3829                 mUiAutomationService.binderDied();
3830             }
3831 
3832             // Unbind all services.
3833             unbindAllServicesLocked(this);
3834 
3835             // Clear service management state.
3836             mBoundServices.clear();
3837             mBindingServices.clear();
3838 
3839             // Clear event management state.
3840             mHandledFeedbackTypes = 0;
3841             mLastSentClientState = -1;
3842 
3843             // Clear state persisted in settings.
3844             mEnabledServices.clear();
3845             mTouchExplorationGrantedServices.clear();
3846             mIsAccessibilityEnabled = false;
3847             mIsTouchExplorationEnabled = false;
3848             mIsEnhancedWebAccessibilityEnabled = false;
3849             mIsDisplayMagnificationEnabled = false;
3850         }
3851 
destroyUiAutomationService()3852         public void destroyUiAutomationService() {
3853             mUiAutomationService = null;
3854             mUiAutomationServiceClient = null;
3855             if (mUiAutomationServiceOwner != null) {
3856                 mUiAutomationServiceOwner.unlinkToDeath(
3857                         mUiAutomationSerivceOnwerDeathRecipient, 0);
3858                 mUiAutomationServiceOwner = null;
3859             }
3860         }
3861     }
3862 
3863     private final class AccessibilityContentObserver extends ContentObserver {
3864 
3865         private final Uri mAccessibilityEnabledUri = Settings.Secure.getUriFor(
3866                 Settings.Secure.ACCESSIBILITY_ENABLED);
3867 
3868         private final Uri mTouchExplorationEnabledUri = Settings.Secure.getUriFor(
3869                 Settings.Secure.TOUCH_EXPLORATION_ENABLED);
3870 
3871         private final Uri mDisplayMagnificationEnabledUri = Settings.Secure.getUriFor(
3872                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
3873 
3874         private final Uri mEnabledAccessibilityServicesUri = Settings.Secure.getUriFor(
3875                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
3876 
3877         private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure
3878                 .getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
3879 
3880         private final Uri mEnhancedWebAccessibilityUri = Settings.Secure
3881                 .getUriFor(Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION);
3882 
3883         private final Uri mDisplayInversionEnabledUri = Settings.Secure.getUriFor(
3884                 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
3885 
3886         private final Uri mDisplayDaltonizerEnabledUri = Settings.Secure.getUriFor(
3887                 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED);
3888 
3889         private final Uri mDisplayDaltonizerUri = Settings.Secure.getUriFor(
3890                 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER);
3891 
3892         private final Uri mHighTextContrastUri = Settings.Secure.getUriFor(
3893                 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED);
3894 
AccessibilityContentObserver(Handler handler)3895         public AccessibilityContentObserver(Handler handler) {
3896             super(handler);
3897         }
3898 
register(ContentResolver contentResolver)3899         public void register(ContentResolver contentResolver) {
3900             contentResolver.registerContentObserver(mAccessibilityEnabledUri,
3901                     false, this, UserHandle.USER_ALL);
3902             contentResolver.registerContentObserver(mTouchExplorationEnabledUri,
3903                     false, this, UserHandle.USER_ALL);
3904             contentResolver.registerContentObserver(mDisplayMagnificationEnabledUri,
3905                     false, this, UserHandle.USER_ALL);
3906             contentResolver.registerContentObserver(mEnabledAccessibilityServicesUri,
3907                     false, this, UserHandle.USER_ALL);
3908             contentResolver.registerContentObserver(
3909                     mTouchExplorationGrantedAccessibilityServicesUri,
3910                     false, this, UserHandle.USER_ALL);
3911             contentResolver.registerContentObserver(mEnhancedWebAccessibilityUri,
3912                     false, this, UserHandle.USER_ALL);
3913             contentResolver.registerContentObserver(
3914                     mDisplayInversionEnabledUri, false, this, UserHandle.USER_ALL);
3915             contentResolver.registerContentObserver(
3916                     mDisplayDaltonizerEnabledUri, false, this, UserHandle.USER_ALL);
3917             contentResolver.registerContentObserver(
3918                     mDisplayDaltonizerUri, false, this, UserHandle.USER_ALL);
3919             contentResolver.registerContentObserver(
3920                     mHighTextContrastUri, false, this, UserHandle.USER_ALL);
3921         }
3922 
3923         @Override
onChange(boolean selfChange, Uri uri)3924         public void onChange(boolean selfChange, Uri uri) {
3925             synchronized (mLock) {
3926                 // Profiles share the accessibility state of the parent. Therefore,
3927                 // we are checking for changes only the parent settings.
3928                 UserState userState = getCurrentUserStateLocked();
3929 
3930                 // We will update when the automation service dies.
3931                 if (userState.mUiAutomationService != null) {
3932                     return;
3933                 }
3934 
3935                 if (mAccessibilityEnabledUri.equals(uri)) {
3936                     if (readAccessibilityEnabledSettingLocked(userState)) {
3937                         onUserStateChangedLocked(userState);
3938                     }
3939                 } else if (mTouchExplorationEnabledUri.equals(uri)) {
3940                     if (readTouchExplorationEnabledSettingLocked(userState)) {
3941                         onUserStateChangedLocked(userState);
3942                     }
3943                 } else if (mDisplayMagnificationEnabledUri.equals(uri)) {
3944                     if (readDisplayMagnificationEnabledSettingLocked(userState)) {
3945                         onUserStateChangedLocked(userState);
3946                     }
3947                 } else if (mEnabledAccessibilityServicesUri.equals(uri)) {
3948                     if (readEnabledAccessibilityServicesLocked(userState)) {
3949                         onUserStateChangedLocked(userState);
3950                     }
3951                 } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) {
3952                     if (readTouchExplorationGrantedAccessibilityServicesLocked(userState)) {
3953                         onUserStateChangedLocked(userState);
3954                     }
3955                 } else if (mEnhancedWebAccessibilityUri.equals(uri)) {
3956                     if (readEnhancedWebAccessibilityEnabledChangedLocked(userState)) {
3957                         onUserStateChangedLocked(userState);
3958                     }
3959                 } else if (mDisplayInversionEnabledUri.equals(uri)
3960                         || mDisplayDaltonizerEnabledUri.equals(uri)
3961                         || mDisplayDaltonizerUri.equals(uri)) {
3962                     if (readDisplayColorAdjustmentSettingsLocked(userState)) {
3963                         updateDisplayColorAdjustmentSettingsLocked(userState);
3964                     }
3965                 } else if (mHighTextContrastUri.equals(uri)) {
3966                     if (readHighTextContrastEnabledSettingLocked(userState)) {
3967                         onUserStateChangedLocked(userState);
3968                     }
3969                 }
3970             }
3971         }
3972     }
3973 }
3974