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