• 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 import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
21 
22 import android.Manifest;
23 import android.accessibilityservice.AccessibilityService;
24 import android.accessibilityservice.AccessibilityServiceInfo;
25 import android.accessibilityservice.IAccessibilityServiceClient;
26 import android.accessibilityservice.IAccessibilityServiceConnection;
27 import android.app.AlertDialog;
28 import android.app.PendingIntent;
29 import android.app.StatusBarManager;
30 import android.content.BroadcastReceiver;
31 import android.content.ComponentName;
32 import android.content.ContentResolver;
33 import android.content.Context;
34 import android.content.DialogInterface;
35 import android.content.DialogInterface.OnClickListener;
36 import android.content.Intent;
37 import android.content.IntentFilter;
38 import android.content.ServiceConnection;
39 import android.content.pm.PackageManager;
40 import android.content.pm.ResolveInfo;
41 import android.content.pm.ServiceInfo;
42 import android.database.ContentObserver;
43 import android.graphics.Point;
44 import android.graphics.Rect;
45 import android.hardware.display.DisplayManager;
46 import android.hardware.input.InputManager;
47 import android.net.Uri;
48 import android.os.Binder;
49 import android.os.Build;
50 import android.os.Bundle;
51 import android.os.Handler;
52 import android.os.IBinder;
53 import android.os.Looper;
54 import android.os.Message;
55 import android.os.Process;
56 import android.os.RemoteCallbackList;
57 import android.os.RemoteException;
58 import android.os.ServiceManager;
59 import android.os.SystemClock;
60 import android.os.UserHandle;
61 import android.os.UserManager;
62 import android.provider.Settings;
63 import android.text.TextUtils;
64 import android.text.TextUtils.SimpleStringSplitter;
65 import android.util.Slog;
66 import android.util.SparseArray;
67 import android.view.Display;
68 import android.view.IWindow;
69 import android.view.IWindowManager;
70 import android.view.InputDevice;
71 import android.view.KeyCharacterMap;
72 import android.view.KeyEvent;
73 import android.view.WindowInfo;
74 import android.view.WindowManager;
75 import android.view.accessibility.AccessibilityEvent;
76 import android.view.accessibility.AccessibilityInteractionClient;
77 import android.view.accessibility.AccessibilityManager;
78 import android.view.accessibility.AccessibilityNodeInfo;
79 import android.view.accessibility.IAccessibilityInteractionConnection;
80 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
81 import android.view.accessibility.IAccessibilityManager;
82 import android.view.accessibility.IAccessibilityManagerClient;
83 
84 import com.android.internal.R;
85 import com.android.internal.content.PackageMonitor;
86 import com.android.internal.statusbar.IStatusBarService;
87 
88 import org.xmlpull.v1.XmlPullParserException;
89 
90 import java.io.IOException;
91 import java.util.ArrayList;
92 import java.util.Arrays;
93 import java.util.HashMap;
94 import java.util.HashSet;
95 import java.util.Iterator;
96 import java.util.List;
97 import java.util.Map;
98 import java.util.Set;
99 import java.util.concurrent.CopyOnWriteArrayList;
100 
101 /**
102  * This class is instantiated by the system as a system level service and can be
103  * accessed only by the system. The task of this service is to be a centralized
104  * event dispatch for {@link AccessibilityEvent}s generated across all processes
105  * on the device. Events are dispatched to {@link AccessibilityService}s.
106  *
107  * @hide
108  */
109 public class AccessibilityManagerService extends IAccessibilityManager.Stub {
110 
111     private static final boolean DEBUG = false;
112 
113     private static final String LOG_TAG = "AccessibilityManagerService";
114 
115     // TODO: This is arbitrary. When there is time implement this by watching
116     //       when that accessibility services are bound.
117     private static final int WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS = 3000;
118 
119     private static final String FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE =
120         "registerUiTestAutomationService";
121 
122     private static final String TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED =
123             "temporaryEnableAccessibilityStateUntilKeyguardRemoved";
124 
125     private static final char COMPONENT_NAME_SEPARATOR = ':';
126 
127     private static final int OWN_PROCESS_ID = android.os.Process.myPid();
128 
129     private static int sIdCounter = 0;
130 
131     private static int sNextWindowId;
132 
133     private final Context mContext;
134 
135     private final Object mLock = new Object();
136 
137     private final SimpleStringSplitter mStringColonSplitter =
138             new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
139 
140     private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList =
141             new ArrayList<AccessibilityServiceInfo>();
142 
143     private final Rect mTempRect = new Rect();
144 
145     private final Point mTempPoint = new Point();
146 
147     private final Display mDefaultDisplay;
148 
149     private final PackageManager mPackageManager;
150 
151     private final IWindowManager mWindowManagerService;
152 
153     private final SecurityPolicy mSecurityPolicy;
154 
155     private final MainHandler mMainHandler;
156 
157     private Service mUiAutomationService;
158 
159     private Service mQueryBridge;
160 
161     private AlertDialog mEnableTouchExplorationDialog;
162 
163     private AccessibilityInputFilter mInputFilter;
164 
165     private boolean mHasInputFilter;
166 
167     private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients =
168             new RemoteCallbackList<IAccessibilityManagerClient>();
169 
170     private final SparseArray<AccessibilityConnectionWrapper> mGlobalInteractionConnections =
171             new SparseArray<AccessibilityConnectionWrapper>();
172 
173     private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<IBinder>();
174 
175     private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
176 
177     private final TempUserStateChangeMemento mTempStateChangeForCurrentUserMemento =
178             new TempUserStateChangeMemento();
179 
180     private int mCurrentUserId = UserHandle.USER_OWNER;
181 
getCurrentUserStateLocked()182     private UserState getCurrentUserStateLocked() {
183         return getUserStateLocked(mCurrentUserId);
184     }
185 
getUserStateLocked(int userId)186     private UserState getUserStateLocked(int userId) {
187         UserState state = mUserStates.get(userId);
188         if (state == null) {
189             state = new UserState(userId);
190             mUserStates.put(userId, state);
191         }
192         return state;
193     }
194 
195     /**
196      * Creates a new instance.
197      *
198      * @param context A {@link Context} instance.
199      */
AccessibilityManagerService(Context context)200     public AccessibilityManagerService(Context context) {
201         mContext = context;
202         mPackageManager = mContext.getPackageManager();
203         mWindowManagerService = (IWindowManager) ServiceManager.getService(Context.WINDOW_SERVICE);
204         mSecurityPolicy = new SecurityPolicy();
205         mMainHandler = new MainHandler(mContext.getMainLooper());
206         //TODO: (multi-display) We need to support multiple displays.
207         DisplayManager displayManager = (DisplayManager)
208                 mContext.getSystemService(Context.DISPLAY_SERVICE);
209         mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
210         registerBroadcastReceivers();
211         new AccessibilityContentObserver(mMainHandler).register(
212                 context.getContentResolver());
213     }
214 
registerBroadcastReceivers()215     private void registerBroadcastReceivers() {
216         PackageMonitor monitor = new PackageMonitor() {
217             @Override
218             public void onSomePackagesChanged() {
219                 synchronized (mLock) {
220                     if (getChangingUserId() != mCurrentUserId) {
221                         return;
222                     }
223                     // We will update when the automation service dies.
224                     if (mUiAutomationService == null) {
225                         UserState userState = getCurrentUserStateLocked();
226                         populateInstalledAccessibilityServiceLocked(userState);
227                         manageServicesLocked(userState);
228                     }
229                 }
230             }
231 
232             @Override
233             public void onPackageRemoved(String packageName, int uid) {
234                 synchronized (mLock) {
235                     final int userId = getChangingUserId();
236                     if (userId != mCurrentUserId) {
237                         return;
238                     }
239                     UserState state = getUserStateLocked(userId);
240                     Iterator<ComponentName> it = state.mEnabledServices.iterator();
241                     while (it.hasNext()) {
242                         ComponentName comp = it.next();
243                         String compPkg = comp.getPackageName();
244                         if (compPkg.equals(packageName)) {
245                             it.remove();
246                             // Update the enabled services setting.
247                             persistComponentNamesToSettingLocked(
248                                     Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
249                                     state.mEnabledServices, userId);
250                             // Update the touch exploration granted services setting.
251                             state.mTouchExplorationGrantedServices.remove(comp);
252                             persistComponentNamesToSettingLocked(
253                                     Settings.Secure.
254                                             TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
255                                     state.mEnabledServices, userId);
256                             return;
257                         }
258                     }
259                 }
260             }
261 
262             @Override
263             public boolean onHandleForceStop(Intent intent, String[] packages,
264                     int uid, boolean doit) {
265                 synchronized (mLock) {
266                     final int userId = getChangingUserId();
267                     if (userId != mCurrentUserId) {
268                         return false;
269                     }
270                     UserState state = getUserStateLocked(userId);
271                     Iterator<ComponentName> it = state.mEnabledServices.iterator();
272                     while (it.hasNext()) {
273                         ComponentName comp = it.next();
274                         String compPkg = comp.getPackageName();
275                         for (String pkg : packages) {
276                             if (compPkg.equals(pkg)) {
277                                 if (!doit) {
278                                     return true;
279                                 }
280                                 it.remove();
281                                 persistComponentNamesToSettingLocked(
282                                         Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
283                                         state.mEnabledServices, userId);
284                             }
285                         }
286                     }
287                     return false;
288                 }
289             }
290         };
291 
292         // package changes
293         monitor.register(mContext, null,  UserHandle.ALL, true);
294 
295         // user change and unlock
296         IntentFilter intentFilter = new IntentFilter();
297         intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
298         intentFilter.addAction(Intent.ACTION_USER_REMOVED);
299         intentFilter.addAction(Intent.ACTION_USER_PRESENT);
300 
301         mContext.registerReceiverAsUser(new BroadcastReceiver() {
302             @Override
303             public void onReceive(Context context, Intent intent) {
304                 String action = intent.getAction();
305                 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
306                     switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
307                 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
308                     removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
309                 } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
310                     restoreStateFromMementoIfNeeded();
311                 }
312             }
313         }, UserHandle.ALL, intentFilter, null, null);
314     }
315 
addClient(IAccessibilityManagerClient client, int userId)316     public int addClient(IAccessibilityManagerClient client, int userId) {
317         synchronized (mLock) {
318             final int resolvedUserId = mSecurityPolicy
319                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
320             // If the client is from a process that runs across users such as
321             // the system UI or the system we add it to the global state that
322             // is shared across users.
323             UserState userState = getUserStateLocked(resolvedUserId);
324             if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
325                 mGlobalClients.register(client);
326                 if (DEBUG) {
327                     Slog.i(LOG_TAG, "Added global client for pid:" + Binder.getCallingPid());
328                 }
329                 return getClientState(userState);
330             } else {
331                 userState.mClients.register(client);
332                 // If this client is not for the current user we do not
333                 // return a state since it is not for the foreground user.
334                 // We will send the state to the client on a user switch.
335                 if (DEBUG) {
336                     Slog.i(LOG_TAG, "Added user client for pid:" + Binder.getCallingPid()
337                             + " and userId:" + mCurrentUserId);
338                 }
339                 return (resolvedUserId == mCurrentUserId) ? getClientState(userState) : 0;
340             }
341         }
342     }
343 
sendAccessibilityEvent(AccessibilityEvent event, int userId)344     public boolean sendAccessibilityEvent(AccessibilityEvent event, int userId) {
345         synchronized (mLock) {
346             final int resolvedUserId = mSecurityPolicy
347                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
348             // This method does nothing for a background user.
349             if (resolvedUserId != mCurrentUserId) {
350                 return true; // yes, recycle the event
351             }
352             if (mSecurityPolicy.canDispatchAccessibilityEvent(event)) {
353                 mSecurityPolicy.updateEventSourceLocked(event);
354                 mMainHandler.obtainMessage(MainHandler.MSG_UPDATE_ACTIVE_WINDOW,
355                         event.getWindowId(), event.getEventType()).sendToTarget();
356                 notifyAccessibilityServicesDelayedLocked(event, false);
357                 notifyAccessibilityServicesDelayedLocked(event, true);
358             }
359             if (mHasInputFilter && mInputFilter != null) {
360                 mMainHandler.obtainMessage(MainHandler.MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER,
361                         AccessibilityEvent.obtain(event)).sendToTarget();
362             }
363             event.recycle();
364             getUserStateLocked(resolvedUserId).mHandledFeedbackTypes = 0;
365         }
366         return (OWN_PROCESS_ID != Binder.getCallingPid());
367     }
368 
getInstalledAccessibilityServiceList(int userId)369     public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
370         synchronized (mLock) {
371             final int resolvedUserId = mSecurityPolicy
372                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
373             return getUserStateLocked(resolvedUserId).mInstalledServices;
374         }
375     }
376 
getEnabledAccessibilityServiceList(int feedbackType, int userId)377     public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType,
378             int userId) {
379         List<AccessibilityServiceInfo> result = null;
380         synchronized (mLock) {
381             final int resolvedUserId = mSecurityPolicy
382                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
383             result = mEnabledServicesForFeedbackTempList;
384             result.clear();
385             List<Service> services = getUserStateLocked(resolvedUserId).mServices;
386             while (feedbackType != 0) {
387                 final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackType));
388                 feedbackType &= ~feedbackTypeBit;
389                 final int serviceCount = services.size();
390                 for (int i = 0; i < serviceCount; i++) {
391                     Service service = services.get(i);
392                     if ((service.mFeedbackType & feedbackTypeBit) != 0) {
393                         result.add(service.mAccessibilityServiceInfo);
394                     }
395                 }
396             }
397         }
398         return result;
399     }
400 
interrupt(int userId)401     public void interrupt(int userId) {
402         CopyOnWriteArrayList<Service> services;
403         synchronized (mLock) {
404             final int resolvedUserId = mSecurityPolicy
405                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
406             // This method does nothing for a background user.
407             if (resolvedUserId != mCurrentUserId) {
408                 return;
409             }
410             services = getUserStateLocked(resolvedUserId).mServices;
411         }
412         for (int i = 0, count = services.size(); i < count; i++) {
413             Service service = services.get(i);
414             try {
415                 service.mServiceInterface.onInterrupt();
416             } catch (RemoteException re) {
417                 Slog.e(LOG_TAG, "Error during sending interrupt request to "
418                     + service.mService, re);
419             }
420         }
421     }
422 
addAccessibilityInteractionConnection(IWindow windowToken, IAccessibilityInteractionConnection connection, int userId)423     public int addAccessibilityInteractionConnection(IWindow windowToken,
424             IAccessibilityInteractionConnection connection, int userId) throws RemoteException {
425         synchronized (mLock) {
426             final int resolvedUserId = mSecurityPolicy
427                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
428             final int windowId = sNextWindowId++;
429             // If the window is from a process that runs across users such as
430             // the system UI or the system we add it to the global state that
431             // is shared across users.
432             if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
433                 AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
434                         windowId, connection, UserHandle.USER_ALL);
435                 wrapper.linkToDeath();
436                 mGlobalInteractionConnections.put(windowId, wrapper);
437                 mGlobalWindowTokens.put(windowId, windowToken.asBinder());
438                 if (DEBUG) {
439                     Slog.i(LOG_TAG, "Added global connection for pid:" + Binder.getCallingPid()
440                             + " with windowId: " + windowId);
441                 }
442             } else {
443                 AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
444                         windowId, connection, resolvedUserId);
445                 wrapper.linkToDeath();
446                 UserState userState = getUserStateLocked(resolvedUserId);
447                 userState.mInteractionConnections.put(windowId, wrapper);
448                 userState.mWindowTokens.put(windowId, windowToken.asBinder());
449                 if (DEBUG) {
450                     Slog.i(LOG_TAG, "Added user connection for pid:" + Binder.getCallingPid()
451                             + " with windowId: " + windowId + " and userId:" + mCurrentUserId);
452                 }
453             }
454             if (DEBUG) {
455                 Slog.i(LOG_TAG, "Adding interaction connection to windowId: " + windowId);
456             }
457             return windowId;
458         }
459     }
460 
removeAccessibilityInteractionConnection(IWindow window)461     public void removeAccessibilityInteractionConnection(IWindow window) {
462         synchronized (mLock) {
463             mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
464                     UserHandle.getCallingUserId());
465             IBinder token = window.asBinder();
466             final int removedWindowId = removeAccessibilityInteractionConnectionInternalLocked(
467                     token, mGlobalWindowTokens, mGlobalInteractionConnections);
468             if (removedWindowId >= 0) {
469                 if (DEBUG) {
470                     Slog.i(LOG_TAG, "Removed global connection for pid:" + Binder.getCallingPid()
471                             + " with windowId: " + removedWindowId);
472                 }
473                 return;
474             }
475             final int userCount = mUserStates.size();
476             for (int i = 0; i < userCount; i++) {
477                 UserState userState = mUserStates.valueAt(i);
478                 final int removedWindowIdForUser =
479                         removeAccessibilityInteractionConnectionInternalLocked(
480                         token, userState.mWindowTokens, userState.mInteractionConnections);
481                 if (removedWindowIdForUser >= 0) {
482                     if (DEBUG) {
483                         Slog.i(LOG_TAG, "Removed user connection for pid:" + Binder.getCallingPid()
484                                 + " with windowId: " + removedWindowIdForUser + " and userId:"
485                                 + mUserStates.keyAt(i));
486                     }
487                     return;
488                 }
489             }
490         }
491     }
492 
removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken, SparseArray<IBinder> windowTokens, SparseArray<AccessibilityConnectionWrapper> interactionConnections)493     private int removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken,
494             SparseArray<IBinder> windowTokens,
495             SparseArray<AccessibilityConnectionWrapper> interactionConnections) {
496         final int count = windowTokens.size();
497         for (int i = 0; i < count; i++) {
498             if (windowTokens.valueAt(i) == windowToken) {
499                 final int windowId = windowTokens.keyAt(i);
500                 windowTokens.removeAt(i);
501                 AccessibilityConnectionWrapper wrapper = interactionConnections.get(windowId);
502                 wrapper.unlinkToDeath();
503                 interactionConnections.remove(windowId);
504                 return windowId;
505             }
506         }
507         return -1;
508     }
509 
registerUiTestAutomationService(IAccessibilityServiceClient serviceClient, AccessibilityServiceInfo accessibilityServiceInfo)510     public void registerUiTestAutomationService(IAccessibilityServiceClient serviceClient,
511             AccessibilityServiceInfo accessibilityServiceInfo) {
512         mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
513                 FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE);
514         ComponentName componentName = new ComponentName("foo.bar",
515                 "AutomationAccessibilityService");
516         synchronized (mLock) {
517             // If an automation services is connected to the system all services are stopped
518             // so the automation one is the only one running. Settings are not changed so when
519             // the automation service goes away the state is restored from the settings.
520             UserState userState = getCurrentUserStateLocked();
521             unbindAllServicesLocked(userState);
522 
523             // If necessary enable accessibility and announce that.
524             if (!userState.mIsAccessibilityEnabled) {
525                 userState.mIsAccessibilityEnabled = true;
526             }
527             // No touch exploration.
528             userState.mIsTouchExplorationEnabled = false;
529 
530             // Hook the automation service up.
531             mUiAutomationService = new Service(mCurrentUserId, componentName,
532                     accessibilityServiceInfo, true);
533             mUiAutomationService.onServiceConnected(componentName, serviceClient.asBinder());
534 
535             updateInputFilterLocked(userState);
536             scheduleSendStateToClientsLocked(userState);
537         }
538     }
539 
temporaryEnableAccessibilityStateUntilKeyguardRemoved( ComponentName service, boolean touchExplorationEnabled)540     public void temporaryEnableAccessibilityStateUntilKeyguardRemoved(
541             ComponentName service, boolean touchExplorationEnabled) {
542         mSecurityPolicy.enforceCallingPermission(
543                 Manifest.permission.TEMPORARY_ENABLE_ACCESSIBILITY,
544                 TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED);
545         try {
546             if (!mWindowManagerService.isKeyguardLocked()) {
547                 return;
548             }
549         } catch (RemoteException re) {
550             return;
551         }
552         synchronized (mLock) {
553             UserState userState = getCurrentUserStateLocked();
554             // Stash the old state so we can restore it when the keyguard is gone.
555             mTempStateChangeForCurrentUserMemento.initialize(mCurrentUserId, getCurrentUserStateLocked());
556             // Set the temporary state.
557             userState.mIsAccessibilityEnabled = true;
558             userState.mIsTouchExplorationEnabled= touchExplorationEnabled;
559             userState.mIsDisplayMagnificationEnabled = false;
560             userState.mEnabledServices.clear();
561             userState.mEnabledServices.add(service);
562             userState.mTouchExplorationGrantedServices.clear();
563             userState.mTouchExplorationGrantedServices.add(service);
564             // Update the internal state.
565             performServiceManagementLocked(userState);
566             updateInputFilterLocked(userState);
567             scheduleSendStateToClientsLocked(userState);
568         }
569     }
570 
unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient)571     public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) {
572         synchronized (mLock) {
573             // Automation service is not bound, so pretend it died to perform clean up.
574             if (mUiAutomationService != null && mUiAutomationService.mServiceInterface != null
575                     && serviceClient != null && mUiAutomationService.mServiceInterface
576                             .asBinder() == serviceClient.asBinder()) {
577                 mUiAutomationService.binderDied();
578             }
579         }
580     }
581 
onGesture(int gestureId)582     boolean onGesture(int gestureId) {
583         synchronized (mLock) {
584             boolean handled = notifyGestureLocked(gestureId, false);
585             if (!handled) {
586                 handled = notifyGestureLocked(gestureId, true);
587             }
588             return handled;
589         }
590     }
591 
592     /**
593      * Gets the bounds of the accessibility focus in the active window.
594      *
595      * @param outBounds The output to which to write the focus bounds.
596      * @return Whether accessibility focus was found and the bounds are populated.
597      */
598     // TODO: (multi-display) Make sure this works for multiple displays.
getAccessibilityFocusBoundsInActiveWindow(Rect outBounds)599     boolean getAccessibilityFocusBoundsInActiveWindow(Rect outBounds) {
600         // Instead of keeping track of accessibility focus events per
601         // window to be able to find the focus in the active window,
602         // we take a stateless approach and look it up. This is fine
603         // since we do this only when the user clicks/long presses.
604         Service service = getQueryBridge();
605         final int connectionId = service.mId;
606         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
607         client.addConnection(connectionId, service);
608         try {
609             AccessibilityNodeInfo root = AccessibilityInteractionClient.getInstance()
610                     .getRootInActiveWindow(connectionId);
611             if (root == null) {
612                 return false;
613             }
614             AccessibilityNodeInfo focus = root.findFocus(
615                     AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
616             if (focus == null) {
617                 return false;
618             }
619             focus.getBoundsInScreen(outBounds);
620             // Clip to the window rectangle.
621             Rect windowBounds = mTempRect;
622             getActiveWindowBounds(windowBounds);
623             outBounds.intersect(windowBounds);
624             // Clip to the screen rectangle.
625             mDefaultDisplay.getRealSize(mTempPoint);
626             outBounds.intersect(0,  0,  mTempPoint.x, mTempPoint.y);
627             return true;
628         } finally {
629             client.removeConnection(connectionId);
630         }
631     }
632 
633     /**
634      * Gets the bounds of the active window.
635      *
636      * @param outBounds The output to which to write the bounds.
637      */
getActiveWindowBounds(Rect outBounds)638     boolean getActiveWindowBounds(Rect outBounds) {
639         IBinder token;
640         synchronized (mLock) {
641             final int windowId = mSecurityPolicy.mActiveWindowId;
642             token = mGlobalWindowTokens.get(windowId);
643             if (token == null) {
644                 token = getCurrentUserStateLocked().mWindowTokens.get(windowId);
645             }
646         }
647         WindowInfo info = null;
648         try {
649             info = mWindowManagerService.getWindowInfo(token);
650             if (info != null) {
651                 outBounds.set(info.frame);
652                 return true;
653             }
654         } catch (RemoteException re) {
655             /* ignore */
656         } finally {
657             if (info != null) {
658                 info.recycle();
659             }
660         }
661         return false;
662     }
663 
getActiveWindowId()664     int getActiveWindowId() {
665         return mSecurityPolicy.mActiveWindowId;
666     }
667 
onTouchInteractionStart()668     void onTouchInteractionStart() {
669         mSecurityPolicy.onTouchInteractionStart();
670     }
671 
onTouchInteractionEnd()672     void onTouchInteractionEnd() {
673         mSecurityPolicy.onTouchInteractionEnd();
674     }
675 
switchUser(int userId)676     private void switchUser(int userId) {
677         synchronized (mLock) {
678             // The user switched so we do not need to restore the current user
679             // state since we will fully rebuild it when he becomes current again.
680             mTempStateChangeForCurrentUserMemento.clear();
681 
682             // Disconnect from services for the old user.
683             UserState oldUserState = getUserStateLocked(mCurrentUserId);
684             unbindAllServicesLocked(oldUserState);
685 
686             // Disable the local managers for the old user.
687             if (oldUserState.mClients.getRegisteredCallbackCount() > 0) {
688                 mMainHandler.obtainMessage(MainHandler.MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER,
689                         oldUserState.mUserId, 0).sendToTarget();
690             }
691 
692             // Announce user changes only if more that one exist.
693             UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
694             final boolean announceNewUser = userManager.getUsers().size() > 1;
695 
696             // The user changed.
697             mCurrentUserId = userId;
698 
699             // Recreate the internal state for the new user.
700             mMainHandler.obtainMessage(MainHandler.MSG_SEND_RECREATE_INTERNAL_STATE,
701                     mCurrentUserId, 0).sendToTarget();
702 
703             if (announceNewUser) {
704                 // Schedule announcement of the current user if needed.
705                 mMainHandler.sendEmptyMessageDelayed(MainHandler.MSG_ANNOUNCE_NEW_USER_IF_NEEDED,
706                         WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS);
707             }
708         }
709     }
710 
removeUser(int userId)711     private void removeUser(int userId) {
712         synchronized (mLock) {
713             mUserStates.remove(userId);
714         }
715     }
716 
restoreStateFromMementoIfNeeded()717     private void restoreStateFromMementoIfNeeded() {
718         synchronized (mLock) {
719             if (mTempStateChangeForCurrentUserMemento.mUserId != UserHandle.USER_NULL) {
720                 UserState userState = getCurrentUserStateLocked();
721                 // Restore the state from the memento.
722                 mTempStateChangeForCurrentUserMemento.applyTo(userState);
723                 mTempStateChangeForCurrentUserMemento.clear();
724                 // Update the internal state.
725                 performServiceManagementLocked(userState);
726                 updateInputFilterLocked(userState);
727                 scheduleSendStateToClientsLocked(userState);
728             }
729         }
730     }
731 
getQueryBridge()732     private Service getQueryBridge() {
733         if (mQueryBridge == null) {
734             AccessibilityServiceInfo info = new AccessibilityServiceInfo();
735             mQueryBridge = new Service(UserHandle.USER_NULL, null, info, true);
736         }
737         return mQueryBridge;
738     }
739 
notifyGestureLocked(int gestureId, boolean isDefault)740     private boolean notifyGestureLocked(int gestureId, boolean isDefault) {
741         // TODO: Now we are giving the gestures to the last enabled
742         //       service that can handle them which is the last one
743         //       in our list since we write the last enabled as the
744         //       last record in the enabled services setting. Ideally,
745         //       the user should make the call which service handles
746         //       gestures. However, only one service should handle
747         //       gestures to avoid user frustration when different
748         //       behavior is observed from different combinations of
749         //       enabled accessibility services.
750         UserState state = getCurrentUserStateLocked();
751         for (int i = state.mServices.size() - 1; i >= 0; i--) {
752             Service service = state.mServices.get(i);
753             if (service.mRequestTouchExplorationMode && service.mIsDefault == isDefault) {
754                 service.notifyGesture(gestureId);
755                 return true;
756             }
757         }
758         return false;
759     }
760 
761     /**
762      * Removes an AccessibilityInteractionConnection.
763      *
764      * @param windowId The id of the window to which the connection is targeted.
765      * @param userId The id of the user owning the connection. UserHandle.USER_ALL
766      *     if global.
767      */
removeAccessibilityInteractionConnectionLocked(int windowId, int userId)768     private void removeAccessibilityInteractionConnectionLocked(int windowId, int userId) {
769         if (userId == UserHandle.USER_ALL) {
770             mGlobalWindowTokens.remove(windowId);
771             mGlobalInteractionConnections.remove(windowId);
772         } else {
773             UserState userState = getCurrentUserStateLocked();
774             userState.mWindowTokens.remove(windowId);
775             userState.mInteractionConnections.remove(windowId);
776         }
777         if (DEBUG) {
778             Slog.i(LOG_TAG, "Removing interaction connection to windowId: " + windowId);
779         }
780     }
781 
populateInstalledAccessibilityServiceLocked(UserState userState)782     private void populateInstalledAccessibilityServiceLocked(UserState userState) {
783         userState.mInstalledServices.clear();
784 
785         List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser(
786                 new Intent(AccessibilityService.SERVICE_INTERFACE),
787                 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
788                 mCurrentUserId);
789 
790         for (int i = 0, count = installedServices.size(); i < count; i++) {
791             ResolveInfo resolveInfo = installedServices.get(i);
792             ServiceInfo serviceInfo = resolveInfo.serviceInfo;
793             if (!android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE.equals(
794                     serviceInfo.permission)) {
795                 Slog.w(LOG_TAG, "Skipping accessibilty service " + new ComponentName(
796                         serviceInfo.packageName, serviceInfo.name).flattenToShortString()
797                         + ": it does not require the permission "
798                         + android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE);
799                 continue;
800             }
801             AccessibilityServiceInfo accessibilityServiceInfo;
802             try {
803                 accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext);
804                 userState.mInstalledServices.add(accessibilityServiceInfo);
805             } catch (XmlPullParserException xppe) {
806                 Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe);
807             } catch (IOException ioe) {
808                 Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", ioe);
809             }
810         }
811     }
812 
populateEnabledAccessibilityServicesLocked(UserState userState)813     private void populateEnabledAccessibilityServicesLocked(UserState userState) {
814         populateComponentNamesFromSettingLocked(
815                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
816                 userState.mUserId,
817                 userState.mEnabledServices);
818     }
819 
populateTouchExplorationGrantedAccessibilityServicesLocked( UserState userState)820     private void populateTouchExplorationGrantedAccessibilityServicesLocked(
821             UserState userState) {
822         populateComponentNamesFromSettingLocked(
823                 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
824                 userState.mUserId,
825                 userState.mTouchExplorationGrantedServices);
826     }
827 
828     /**
829      * Performs {@link AccessibilityService}s delayed notification. The delay is configurable
830      * and denotes the period after the last event before notifying the service.
831      *
832      * @param event The event.
833      * @param isDefault True to notify default listeners, not default services.
834      */
notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event, boolean isDefault)835     private void notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event,
836             boolean isDefault) {
837         try {
838             UserState state = getCurrentUserStateLocked();
839             for (int i = 0, count = state.mServices.size(); i < count; i++) {
840                 Service service = state.mServices.get(i);
841 
842                 if (service.mIsDefault == isDefault) {
843                     if (canDispathEventLocked(service, event, state.mHandledFeedbackTypes)) {
844                         state.mHandledFeedbackTypes |= service.mFeedbackType;
845                         service.notifyAccessibilityEvent(event);
846                     }
847                 }
848             }
849         } catch (IndexOutOfBoundsException oobe) {
850             // An out of bounds exception can happen if services are going away
851             // as the for loop is running. If that happens, just bail because
852             // there are no more services to notify.
853             return;
854         }
855     }
856 
857     /**
858      * Adds a service for a user.
859      *
860      * @param service The service to add.
861      * @param userId The user id.
862      */
tryAddServiceLocked(Service service, int userId)863     private void tryAddServiceLocked(Service service, int userId) {
864         try {
865             UserState userState = getUserStateLocked(userId);
866             if (userState.mServices.contains(service)) {
867                 return;
868             }
869             service.linkToOwnDeath();
870             userState.mServices.add(service);
871             userState.mComponentNameToServiceMap.put(service.mComponentName, service);
872             updateInputFilterLocked(userState);
873             tryEnableTouchExplorationLocked(service);
874         } catch (RemoteException e) {
875             /* do nothing */
876         }
877     }
878 
879     /**
880      * Removes a service.
881      *
882      * @param service The service.
883      * @return True if the service was removed, false otherwise.
884      */
tryRemoveServiceLocked(Service service)885     private boolean tryRemoveServiceLocked(Service service) {
886         UserState userState = getUserStateLocked(service.mUserId);
887         final boolean removed = userState.mServices.remove(service);
888         if (!removed) {
889             return false;
890         }
891         userState.mComponentNameToServiceMap.remove(service.mComponentName);
892         service.unlinkToOwnDeath();
893         service.dispose();
894         updateInputFilterLocked(userState);
895         tryDisableTouchExplorationLocked(service);
896         return removed;
897     }
898 
899     /**
900      * Determines if given event can be dispatched to a service based on the package of the
901      * event source and already notified services for that event type. Specifically, a
902      * service is notified if it is interested in events from the package and no other service
903      * providing the same feedback type has been notified. Exception are services the
904      * provide generic feedback (feedback type left as a safety net for unforeseen feedback
905      * types) which are always notified.
906      *
907      * @param service The potential receiver.
908      * @param event The event.
909      * @param handledFeedbackTypes The feedback types for which services have been notified.
910      * @return True if the listener should be notified, false otherwise.
911      */
canDispathEventLocked(Service service, AccessibilityEvent event, int handledFeedbackTypes)912     private boolean canDispathEventLocked(Service service, AccessibilityEvent event,
913             int handledFeedbackTypes) {
914 
915         if (!service.canReceiveEvents()) {
916             return false;
917         }
918 
919         if (!event.isImportantForAccessibility()
920                 && !service.mIncludeNotImportantViews) {
921             return false;
922         }
923 
924         int eventType = event.getEventType();
925         if ((service.mEventTypes & eventType) != eventType) {
926             return false;
927         }
928 
929         Set<String> packageNames = service.mPackageNames;
930         CharSequence packageName = event.getPackageName();
931 
932         if (packageNames.isEmpty() || packageNames.contains(packageName)) {
933             int feedbackType = service.mFeedbackType;
934             if ((handledFeedbackTypes & feedbackType) != feedbackType
935                     || feedbackType == AccessibilityServiceInfo.FEEDBACK_GENERIC) {
936                 return true;
937             }
938         }
939 
940         return false;
941     }
942 
943     /**
944      * Manages services by starting enabled ones and stopping disabled ones.
945      */
manageServicesLocked(UserState userState)946     private void manageServicesLocked(UserState userState) {
947         final int enabledInstalledServicesCount = updateServicesStateLocked(userState);
948         // No enabled installed services => disable accessibility to avoid
949         // sending accessibility events with no recipient across processes.
950         if (userState.mIsAccessibilityEnabled && enabledInstalledServicesCount == 0) {
951             Settings.Secure.putIntForUser(mContext.getContentResolver(),
952                     Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId);
953         }
954     }
955 
956     /**
957      * Unbinds all bound services for a user.
958      *
959      * @param userState The user state.
960      */
unbindAllServicesLocked(UserState userState)961     private void unbindAllServicesLocked(UserState userState) {
962         List<Service> services = userState.mServices;
963         for (int i = 0, count = services.size(); i < count; i++) {
964             Service service = services.get(i);
965             if (service.unbind()) {
966                 i--;
967                 count--;
968             }
969         }
970     }
971 
972     /**
973      * Populates a set with the {@link ComponentName}s stored in a colon
974      * separated value setting for a given user.
975      *
976      * @param settingName The setting to parse.
977      * @param userId The user id.
978      * @param outComponentNames The output component names.
979      */
populateComponentNamesFromSettingLocked(String settingName, int userId, Set<ComponentName> outComponentNames)980     private void populateComponentNamesFromSettingLocked(String settingName, int userId,
981             Set<ComponentName> outComponentNames) {
982         String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
983                 settingName, userId);
984         outComponentNames.clear();
985         if (settingValue != null) {
986             TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
987             splitter.setString(settingValue);
988             while (splitter.hasNext()) {
989                 String str = splitter.next();
990                 if (str == null || str.length() <= 0) {
991                     continue;
992                 }
993                 ComponentName enabledService = ComponentName.unflattenFromString(str);
994                 if (enabledService != null) {
995                     outComponentNames.add(enabledService);
996                 }
997             }
998         }
999     }
1000 
1001     /**
1002      * Persists the component names in the specified setting in a
1003      * colon separated fashion.
1004      *
1005      * @param settingName The setting name.
1006      * @param componentNames The component names.
1007      */
persistComponentNamesToSettingLocked(String settingName, Set<ComponentName> componentNames, int userId)1008     private void persistComponentNamesToSettingLocked(String settingName,
1009             Set<ComponentName> componentNames, int userId) {
1010         StringBuilder builder = new StringBuilder();
1011         for (ComponentName componentName : componentNames) {
1012             if (builder.length() > 0) {
1013                 builder.append(COMPONENT_NAME_SEPARATOR);
1014             }
1015             builder.append(componentName.flattenToShortString());
1016         }
1017         Settings.Secure.putStringForUser(mContext.getContentResolver(),
1018                 settingName, builder.toString(), userId);
1019     }
1020 
1021     /**
1022      * Updates the state of each service by starting (or keeping running) enabled ones and
1023      * stopping the rest.
1024      *
1025      * @param userState The user state for which to do that.
1026      * @return The number of enabled installed services.
1027      */
updateServicesStateLocked(UserState userState)1028     private int updateServicesStateLocked(UserState userState) {
1029         Map<ComponentName, Service> componentNameToServiceMap =
1030                 userState.mComponentNameToServiceMap;
1031         boolean isEnabled = userState.mIsAccessibilityEnabled;
1032 
1033         int enabledInstalledServices = 0;
1034         for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
1035             AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i);
1036             ComponentName componentName = ComponentName.unflattenFromString(
1037                     installedService.getId());
1038             Service service = componentNameToServiceMap.get(componentName);
1039 
1040             if (isEnabled) {
1041                 if (userState.mEnabledServices.contains(componentName)) {
1042                     if (service == null) {
1043                         service = new Service(userState.mUserId, componentName,
1044                                 installedService, false);
1045                     }
1046                     service.bind();
1047                     enabledInstalledServices++;
1048                 } else {
1049                     if (service != null) {
1050                         service.unbind();
1051                     }
1052                 }
1053             } else {
1054                 if (service != null) {
1055                     service.unbind();
1056                 }
1057             }
1058         }
1059 
1060         return enabledInstalledServices;
1061     }
1062 
scheduleSendStateToClientsLocked(UserState userState)1063     private void scheduleSendStateToClientsLocked(UserState userState) {
1064         if (mGlobalClients.getRegisteredCallbackCount() > 0
1065                 || userState.mClients.getRegisteredCallbackCount() > 0) {
1066             final int clientState = getClientState(userState);
1067             mMainHandler.obtainMessage(MainHandler.MSG_SEND_STATE_TO_CLIENTS,
1068                     clientState, userState.mUserId) .sendToTarget();
1069         }
1070     }
1071 
updateInputFilterLocked(UserState userState)1072     private void updateInputFilterLocked(UserState userState) {
1073         boolean setInputFilter = false;
1074         AccessibilityInputFilter inputFilter = null;
1075         synchronized (mLock) {
1076             if ((userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled)
1077                     || userState.mIsDisplayMagnificationEnabled) {
1078                 if (!mHasInputFilter) {
1079                     mHasInputFilter = true;
1080                     if (mInputFilter == null) {
1081                         mInputFilter = new AccessibilityInputFilter(mContext,
1082                                 AccessibilityManagerService.this);
1083                     }
1084                     inputFilter = mInputFilter;
1085                     setInputFilter = true;
1086                 }
1087                 int flags = 0;
1088                 if (userState.mIsDisplayMagnificationEnabled) {
1089                     flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
1090                 }
1091                 if (userState.mIsTouchExplorationEnabled) {
1092                     flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
1093                 }
1094                 mInputFilter.setEnabledFeatures(flags);
1095             } else {
1096                 if (mHasInputFilter) {
1097                     mHasInputFilter = false;
1098                     mInputFilter.setEnabledFeatures(0);
1099                     inputFilter = null;
1100                     setInputFilter = true;
1101                 }
1102             }
1103         }
1104         if (setInputFilter) {
1105             try {
1106                 mWindowManagerService.setInputFilter(inputFilter);
1107             } catch (RemoteException re) {
1108                 /* ignore */
1109             }
1110         }
1111     }
1112 
showEnableTouchExplorationDialog(final Service service)1113     private void showEnableTouchExplorationDialog(final Service service) {
1114         String label = service.mResolveInfo.loadLabel(
1115                 mContext.getPackageManager()).toString();
1116         synchronized (mLock) {
1117             final UserState state = getCurrentUserStateLocked();
1118             if (state.mIsTouchExplorationEnabled) {
1119                 return;
1120             }
1121             if (mEnableTouchExplorationDialog != null
1122                     && mEnableTouchExplorationDialog.isShowing()) {
1123                 return;
1124             }
1125             mEnableTouchExplorationDialog = new AlertDialog.Builder(mContext)
1126                 .setIcon(android.R.drawable.ic_dialog_alert)
1127                 .setPositiveButton(android.R.string.ok, new OnClickListener() {
1128                     @Override
1129                     public void onClick(DialogInterface dialog, int which) {
1130                         // The user allowed the service to toggle touch exploration.
1131                         state.mTouchExplorationGrantedServices.add(service.mComponentName);
1132                         persistComponentNamesToSettingLocked(
1133                                 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
1134                                        state.mTouchExplorationGrantedServices, state.mUserId);
1135                         // Enable touch exploration.
1136                         Settings.Secure.putIntForUser(mContext.getContentResolver(),
1137                                 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1,
1138                                 service.mUserId);
1139                     }
1140                 })
1141                 .setNegativeButton(android.R.string.cancel, new OnClickListener() {
1142                     @Override
1143                     public void onClick(DialogInterface dialog, int which) {
1144                         dialog.dismiss();
1145                     }
1146                 })
1147                 .setTitle(R.string.enable_explore_by_touch_warning_title)
1148                 .setMessage(mContext.getString(
1149                         R.string.enable_explore_by_touch_warning_message, label))
1150                 .create();
1151             mEnableTouchExplorationDialog.getWindow().setType(
1152                     WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1153             mEnableTouchExplorationDialog.getWindow().getAttributes().privateFlags
1154                     |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
1155             mEnableTouchExplorationDialog.setCanceledOnTouchOutside(true);
1156             mEnableTouchExplorationDialog.show();
1157         }
1158     }
1159 
getClientState(UserState userState)1160     private int getClientState(UserState userState) {
1161         int clientState = 0;
1162         if (userState.mIsAccessibilityEnabled) {
1163             clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
1164         }
1165         // Touch exploration relies on enabled accessibility.
1166         if (userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) {
1167             clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
1168         }
1169         return clientState;
1170     }
1171 
recreateInternalStateLocked(UserState userState)1172     private void recreateInternalStateLocked(UserState userState) {
1173         populateInstalledAccessibilityServiceLocked(userState);
1174         populateEnabledAccessibilityServicesLocked(userState);
1175         populateTouchExplorationGrantedAccessibilityServicesLocked(userState);
1176 
1177         handleTouchExplorationEnabledSettingChangedLocked(userState);
1178         handleDisplayMagnificationEnabledSettingChangedLocked(userState);
1179         handleAccessibilityEnabledSettingChangedLocked(userState);
1180 
1181         performServiceManagementLocked(userState);
1182         updateInputFilterLocked(userState);
1183         scheduleSendStateToClientsLocked(userState);
1184     }
1185 
handleAccessibilityEnabledSettingChangedLocked(UserState userState)1186     private void handleAccessibilityEnabledSettingChangedLocked(UserState userState) {
1187         userState.mIsAccessibilityEnabled = Settings.Secure.getIntForUser(
1188                mContext.getContentResolver(),
1189                Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId) == 1;
1190     }
1191 
performServiceManagementLocked(UserState userState)1192     private void performServiceManagementLocked(UserState userState) {
1193         if (userState.mIsAccessibilityEnabled ) {
1194             manageServicesLocked(userState);
1195         } else {
1196             unbindAllServicesLocked(userState);
1197         }
1198     }
1199 
handleTouchExplorationEnabledSettingChangedLocked(UserState userState)1200     private void handleTouchExplorationEnabledSettingChangedLocked(UserState userState) {
1201         userState.mIsTouchExplorationEnabled = Settings.Secure.getIntForUser(
1202                 mContext.getContentResolver(),
1203                 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId) == 1;
1204     }
1205 
handleDisplayMagnificationEnabledSettingChangedLocked(UserState userState)1206     private void handleDisplayMagnificationEnabledSettingChangedLocked(UserState userState) {
1207         userState.mIsDisplayMagnificationEnabled = Settings.Secure.getIntForUser(
1208                 mContext.getContentResolver(),
1209                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
1210                 0, userState.mUserId) == 1;
1211     }
1212 
handleTouchExplorationGrantedAccessibilityServicesChangedLocked( UserState userState)1213     private void handleTouchExplorationGrantedAccessibilityServicesChangedLocked(
1214             UserState userState) {
1215         final int serviceCount = userState.mServices.size();
1216         for (int i = 0; i < serviceCount; i++) {
1217             Service service = userState.mServices.get(i);
1218             if (service.mRequestTouchExplorationMode
1219                     && userState.mTouchExplorationGrantedServices.contains(
1220                             service.mComponentName)) {
1221                 tryEnableTouchExplorationLocked(service);
1222                 return;
1223             }
1224         }
1225         if (userState.mIsTouchExplorationEnabled) {
1226             Settings.Secure.putIntForUser(mContext.getContentResolver(),
1227                     Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId);
1228         }
1229     }
1230 
tryEnableTouchExplorationLocked(final Service service)1231     private void tryEnableTouchExplorationLocked(final Service service) {
1232         UserState userState = getUserStateLocked(service.mUserId);
1233         if (!userState.mIsTouchExplorationEnabled && service.mRequestTouchExplorationMode
1234                 && service.canReceiveEvents()) {
1235             final boolean canToggleTouchExploration =
1236                     userState.mTouchExplorationGrantedServices.contains(service.mComponentName);
1237             if (!service.mIsAutomation && !canToggleTouchExploration) {
1238                 showEnableTouchExplorationDialog(service);
1239             } else {
1240                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
1241                         Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, userState.mUserId);
1242             }
1243         }
1244     }
1245 
tryDisableTouchExplorationLocked(Service service)1246     private void tryDisableTouchExplorationLocked(Service service) {
1247         UserState userState = getUserStateLocked(service.mUserId);
1248         if (userState.mIsTouchExplorationEnabled) {
1249             final int serviceCount = userState.mServices.size();
1250             for (int i = 0; i < serviceCount; i++) {
1251                 Service other = userState.mServices.get(i);
1252                 if (other != service && other.mRequestTouchExplorationMode) {
1253                     return;
1254                 }
1255             }
1256             Settings.Secure.putIntForUser(mContext.getContentResolver(),
1257                     Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId);
1258         }
1259     }
1260 
1261     private class AccessibilityConnectionWrapper implements DeathRecipient {
1262         private final int mWindowId;
1263         private final int mUserId;
1264         private final IAccessibilityInteractionConnection mConnection;
1265 
AccessibilityConnectionWrapper(int windowId, IAccessibilityInteractionConnection connection, int userId)1266         public AccessibilityConnectionWrapper(int windowId,
1267                 IAccessibilityInteractionConnection connection, int userId) {
1268             mWindowId = windowId;
1269             mUserId = userId;
1270             mConnection = connection;
1271         }
1272 
linkToDeath()1273         public void linkToDeath() throws RemoteException {
1274             mConnection.asBinder().linkToDeath(this, 0);
1275         }
1276 
unlinkToDeath()1277         public void unlinkToDeath() {
1278             mConnection.asBinder().unlinkToDeath(this, 0);
1279         }
1280 
1281         @Override
binderDied()1282         public void binderDied() {
1283             unlinkToDeath();
1284             synchronized (mLock) {
1285                 removeAccessibilityInteractionConnectionLocked(mWindowId, mUserId);
1286             }
1287         }
1288     }
1289 
1290     private final class MainHandler extends Handler {
1291         public static final int MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER = 1;
1292         public static final int MSG_SEND_STATE_TO_CLIENTS = 2;
1293         public static final int MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER = 3;
1294         public static final int MSG_SEND_RECREATE_INTERNAL_STATE = 4;
1295         public static final int MSG_UPDATE_ACTIVE_WINDOW = 5;
1296         public static final int MSG_ANNOUNCE_NEW_USER_IF_NEEDED = 6;
1297 
MainHandler(Looper looper)1298         public MainHandler(Looper looper) {
1299             super(looper);
1300         }
1301 
1302         @Override
handleMessage(Message msg)1303         public void handleMessage(Message msg) {
1304             final int type = msg.what;
1305             switch (type) {
1306                 case MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER: {
1307                     AccessibilityEvent event = (AccessibilityEvent) msg.obj;
1308                     synchronized (mLock) {
1309                         if (mHasInputFilter && mInputFilter != null) {
1310                             mInputFilter.notifyAccessibilityEvent(event);
1311                         }
1312                     }
1313                     event.recycle();
1314                 } break;
1315                 case MSG_SEND_STATE_TO_CLIENTS: {
1316                     final int clientState = msg.arg1;
1317                     final int userId = msg.arg2;
1318                     sendStateToClients(clientState, mGlobalClients);
1319                     sendStateToClientsForUser(clientState, userId);
1320                 } break;
1321                 case MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER: {
1322                     final int userId = msg.arg1;
1323                     sendStateToClientsForUser(0, userId);
1324                 } break;
1325                 case MSG_SEND_RECREATE_INTERNAL_STATE: {
1326                     final int userId = msg.arg1;
1327                     synchronized (mLock) {
1328                         UserState userState = getUserStateLocked(userId);
1329                         recreateInternalStateLocked(userState);
1330                     }
1331                 } break;
1332                 case MSG_UPDATE_ACTIVE_WINDOW: {
1333                     final int windowId = msg.arg1;
1334                     final int eventType = msg.arg2;
1335                     mSecurityPolicy.updateActiveWindow(windowId, eventType);
1336                 } break;
1337                 case MSG_ANNOUNCE_NEW_USER_IF_NEEDED: {
1338                     announceNewUserIfNeeded();
1339                 } break;
1340             }
1341         }
1342 
announceNewUserIfNeeded()1343         private void announceNewUserIfNeeded() {
1344             synchronized (mLock) {
1345                 UserState userState = getCurrentUserStateLocked();
1346                 if (userState.mIsAccessibilityEnabled) {
1347                     UserManager userManager = (UserManager) mContext.getSystemService(
1348                             Context.USER_SERVICE);
1349                     String message = mContext.getString(R.string.user_switched,
1350                             userManager.getUserInfo(mCurrentUserId).name);
1351                     AccessibilityEvent event = AccessibilityEvent.obtain(
1352                             AccessibilityEvent.TYPE_ANNOUNCEMENT);
1353                     event.getText().add(message);
1354                     event.setWindowId(mSecurityPolicy.getRetrievalAllowingWindowLocked());
1355                     sendAccessibilityEvent(event, mCurrentUserId);
1356                 }
1357             }
1358         }
1359 
sendStateToClientsForUser(int clientState, int userId)1360         private void sendStateToClientsForUser(int clientState, int userId) {
1361             final UserState userState;
1362             synchronized (mLock) {
1363                 userState = getUserStateLocked(userId);
1364             }
1365             sendStateToClients(clientState, userState.mClients);
1366         }
1367 
sendStateToClients(int clientState, RemoteCallbackList<IAccessibilityManagerClient> clients)1368         private void sendStateToClients(int clientState,
1369                 RemoteCallbackList<IAccessibilityManagerClient> clients) {
1370             try {
1371                 final int userClientCount = clients.beginBroadcast();
1372                 for (int i = 0; i < userClientCount; i++) {
1373                     IAccessibilityManagerClient client = clients.getBroadcastItem(i);
1374                     try {
1375                         client.setState(clientState);
1376                     } catch (RemoteException re) {
1377                         /* ignore */
1378                     }
1379                 }
1380             } finally {
1381                 clients.finishBroadcast();
1382             }
1383         }
1384     }
1385 
1386     /**
1387      * This class represents an accessibility service. It stores all per service
1388      * data required for the service management, provides API for starting/stopping the
1389      * service and is responsible for adding/removing the service in the data structures
1390      * for service management. The class also exposes configuration interface that is
1391      * passed to the service it represents as soon it is bound. It also serves as the
1392      * connection for the service.
1393      */
1394     class Service extends IAccessibilityServiceConnection.Stub
1395             implements ServiceConnection, DeathRecipient {
1396 
1397         // We pick the MSB to avoid collision since accessibility event types are
1398         // used as message types allowing us to remove messages per event type.
1399         private static final int MSG_ON_GESTURE = 0x80000000;
1400 
1401         final int mUserId;
1402 
1403         int mId = 0;
1404 
1405         AccessibilityServiceInfo mAccessibilityServiceInfo;
1406 
1407         IBinder mService;
1408 
1409         IAccessibilityServiceClient mServiceInterface;
1410 
1411         int mEventTypes;
1412 
1413         int mFeedbackType;
1414 
1415         Set<String> mPackageNames = new HashSet<String>();
1416 
1417         boolean mIsDefault;
1418 
1419         boolean mRequestTouchExplorationMode;
1420 
1421         boolean mIncludeNotImportantViews;
1422 
1423         long mNotificationTimeout;
1424 
1425         ComponentName mComponentName;
1426 
1427         Intent mIntent;
1428 
1429         boolean mCanRetrieveScreenContent;
1430 
1431         boolean mIsAutomation;
1432 
1433         final Rect mTempBounds = new Rect();
1434 
1435         final ResolveInfo mResolveInfo;
1436 
1437         // the events pending events to be dispatched to this service
1438         final SparseArray<AccessibilityEvent> mPendingEvents =
1439             new SparseArray<AccessibilityEvent>();
1440 
1441         /**
1442          * Handler for delayed event dispatch.
1443          */
1444         public Handler mHandler = new Handler(mMainHandler.getLooper()) {
1445             @Override
1446             public void handleMessage(Message message) {
1447                 final int type = message.what;
1448                 switch (type) {
1449                     case MSG_ON_GESTURE: {
1450                         final int gestureId = message.arg1;
1451                         notifyGestureInternal(gestureId);
1452                     } break;
1453                     default: {
1454                         final int eventType = type;
1455                         notifyAccessibilityEventInternal(eventType);
1456                     } break;
1457                 }
1458             }
1459         };
1460 
Service(int userId, ComponentName componentName, AccessibilityServiceInfo accessibilityServiceInfo, boolean isAutomation)1461         public Service(int userId, ComponentName componentName,
1462                 AccessibilityServiceInfo accessibilityServiceInfo, boolean isAutomation) {
1463             mUserId = userId;
1464             mResolveInfo = accessibilityServiceInfo.getResolveInfo();
1465             mId = sIdCounter++;
1466             mComponentName = componentName;
1467             mAccessibilityServiceInfo = accessibilityServiceInfo;
1468             mIsAutomation = isAutomation;
1469             if (!isAutomation) {
1470                 mCanRetrieveScreenContent = accessibilityServiceInfo.getCanRetrieveWindowContent();
1471                 mRequestTouchExplorationMode =
1472                     (accessibilityServiceInfo.flags
1473                             & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
1474                 mIntent = new Intent().setComponent(mComponentName);
1475                 mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
1476                         com.android.internal.R.string.accessibility_binding_label);
1477                 mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
1478                         mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0));
1479             } else {
1480                 mCanRetrieveScreenContent = true;
1481             }
1482             setDynamicallyConfigurableProperties(accessibilityServiceInfo);
1483         }
1484 
setDynamicallyConfigurableProperties(AccessibilityServiceInfo info)1485         public void setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) {
1486             mEventTypes = info.eventTypes;
1487             mFeedbackType = info.feedbackType;
1488             String[] packageNames = info.packageNames;
1489             if (packageNames != null) {
1490                 mPackageNames.addAll(Arrays.asList(packageNames));
1491             }
1492             mNotificationTimeout = info.notificationTimeout;
1493             mIsDefault = (info.flags & DEFAULT) != 0;
1494 
1495             if (mIsAutomation || info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion
1496                     >= Build.VERSION_CODES.JELLY_BEAN) {
1497                 mIncludeNotImportantViews =
1498                     (info.flags & FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0;
1499             }
1500 
1501             mRequestTouchExplorationMode = (info.flags
1502                     & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
1503 
1504             // If this service is up and running we may have to enable touch
1505             // exploration, otherwise this will happen when the service connects.
1506             synchronized (mLock) {
1507                 if (canReceiveEvents()) {
1508                     if (mRequestTouchExplorationMode) {
1509                         tryEnableTouchExplorationLocked(this);
1510                     } else {
1511                         tryDisableTouchExplorationLocked(this);
1512                     }
1513                 }
1514             }
1515         }
1516 
1517         /**
1518          * Binds to the accessibility service.
1519          *
1520          * @return True if binding is successful.
1521          */
bind()1522         public boolean bind() {
1523             if (!mIsAutomation && mService == null) {
1524                 return mContext.bindService(mIntent, this, Context.BIND_AUTO_CREATE, mUserId);
1525             }
1526             return false;
1527         }
1528 
1529         /**
1530          * Unbinds form the accessibility service and removes it from the data
1531          * structures for service management.
1532          *
1533          * @return True if unbinding is successful.
1534          */
unbind()1535         public boolean unbind() {
1536             if (mService != null) {
1537                 synchronized (mLock) {
1538                     tryRemoveServiceLocked(this);
1539                 }
1540                 if (!mIsAutomation) {
1541                     mContext.unbindService(this);
1542                 }
1543                 return true;
1544             }
1545             return false;
1546         }
1547 
canReceiveEvents()1548         public boolean canReceiveEvents() {
1549             return (mEventTypes != 0 && mFeedbackType != 0 && mService != null);
1550         }
1551 
1552         @Override
getServiceInfo()1553         public AccessibilityServiceInfo getServiceInfo() {
1554             synchronized (mLock) {
1555                 return mAccessibilityServiceInfo;
1556             }
1557         }
1558 
1559         @Override
setServiceInfo(AccessibilityServiceInfo info)1560         public void setServiceInfo(AccessibilityServiceInfo info) {
1561             final long identity = Binder.clearCallingIdentity();
1562             try {
1563                 synchronized (mLock) {
1564                     // If the XML manifest had data to configure the service its info
1565                     // should be already set. In such a case update only the dynamically
1566                     // configurable properties.
1567                     AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo;
1568                     if (oldInfo != null) {
1569                         oldInfo.updateDynamicallyConfigurableProperties(info);
1570                         setDynamicallyConfigurableProperties(oldInfo);
1571                     } else {
1572                         setDynamicallyConfigurableProperties(info);
1573                     }
1574                 }
1575             } finally {
1576                 Binder.restoreCallingIdentity(identity);
1577             }
1578         }
1579 
1580         @Override
onServiceConnected(ComponentName componentName, IBinder service)1581         public void onServiceConnected(ComponentName componentName, IBinder service) {
1582             mService = service;
1583             mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
1584             try {
1585                 mServiceInterface.setConnection(this, mId);
1586                 synchronized (mLock) {
1587                     tryAddServiceLocked(this, mUserId);
1588                 }
1589             } catch (RemoteException re) {
1590                 Slog.w(LOG_TAG, "Error while setting Controller for service: " + service, re);
1591             }
1592         }
1593 
1594         @Override
findAccessibilityNodeInfoByViewId(int accessibilityWindowId, long accessibilityNodeId, int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)1595         public float findAccessibilityNodeInfoByViewId(int accessibilityWindowId,
1596                 long accessibilityNodeId, int viewId, int interactionId,
1597                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1598                 throws RemoteException {
1599             final int resolvedWindowId;
1600             IAccessibilityInteractionConnection connection = null;
1601             synchronized (mLock) {
1602                 final int resolvedUserId = mSecurityPolicy
1603                         .resolveCallingUserIdEnforcingPermissionsLocked(
1604                                 UserHandle.getCallingUserId());
1605                 if (resolvedUserId != mCurrentUserId) {
1606                     return -1;
1607                 }
1608                 mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1609                 final boolean permissionGranted = mSecurityPolicy.canRetrieveWindowContent(this);
1610                 if (!permissionGranted) {
1611                     return 0;
1612                 } else {
1613                     resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1614                     connection = getConnectionLocked(resolvedWindowId);
1615                     if (connection == null) {
1616                         return 0;
1617                     }
1618                 }
1619             }
1620             final int flags = (mIncludeNotImportantViews) ?
1621                     AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1622             final int interrogatingPid = Binder.getCallingPid();
1623             final long identityToken = Binder.clearCallingIdentity();
1624             try {
1625                 connection.findAccessibilityNodeInfoByViewId(accessibilityNodeId, viewId,
1626                         interactionId, callback, flags, interrogatingPid, interrogatingTid);
1627                 return getCompatibilityScale(resolvedWindowId);
1628             } catch (RemoteException re) {
1629                 if (DEBUG) {
1630                     Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId().");
1631                 }
1632             } finally {
1633                 Binder.restoreCallingIdentity(identityToken);
1634             }
1635             return 0;
1636         }
1637 
1638         @Override
findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId, String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)1639         public float findAccessibilityNodeInfosByText(int accessibilityWindowId,
1640                 long accessibilityNodeId, String text, int interactionId,
1641                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1642                 throws RemoteException {
1643             final int resolvedWindowId;
1644             IAccessibilityInteractionConnection connection = null;
1645             synchronized (mLock) {
1646                 final int resolvedUserId = mSecurityPolicy
1647                         .resolveCallingUserIdEnforcingPermissionsLocked(
1648                         UserHandle.getCallingUserId());
1649                 if (resolvedUserId != mCurrentUserId) {
1650                     return -1;
1651                 }
1652                 mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1653                 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1654                 final boolean permissionGranted =
1655                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
1656                 if (!permissionGranted) {
1657                     return 0;
1658                 } else {
1659                     connection = getConnectionLocked(resolvedWindowId);
1660                     if (connection == null) {
1661                         return 0;
1662                     }
1663                 }
1664             }
1665             final int flags = (mIncludeNotImportantViews) ?
1666                     AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1667             final int interrogatingPid = Binder.getCallingPid();
1668             final long identityToken = Binder.clearCallingIdentity();
1669             try {
1670                 connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
1671                         interactionId, callback, flags, interrogatingPid,
1672                         interrogatingTid);
1673                 return getCompatibilityScale(resolvedWindowId);
1674             } catch (RemoteException re) {
1675                 if (DEBUG) {
1676                     Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()");
1677                 }
1678             } finally {
1679                 Binder.restoreCallingIdentity(identityToken);
1680             }
1681             return 0;
1682         }
1683 
1684         @Override
findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId, long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, long interrogatingTid)1685         public float findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
1686                 long accessibilityNodeId, int interactionId,
1687                 IAccessibilityInteractionConnectionCallback callback, int flags,
1688                 long interrogatingTid) throws RemoteException {
1689             final int resolvedWindowId;
1690             IAccessibilityInteractionConnection connection = null;
1691             synchronized (mLock) {
1692                 final int resolvedUserId = mSecurityPolicy
1693                         .resolveCallingUserIdEnforcingPermissionsLocked(
1694                         UserHandle.getCallingUserId());
1695                 if (resolvedUserId != mCurrentUserId) {
1696                     return -1;
1697                 }
1698                 mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1699                 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1700                 final boolean permissionGranted =
1701                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
1702                 if (!permissionGranted) {
1703                     return 0;
1704                 } else {
1705                     connection = getConnectionLocked(resolvedWindowId);
1706                     if (connection == null) {
1707                         return 0;
1708                     }
1709                 }
1710             }
1711             final int allFlags = flags | ((mIncludeNotImportantViews) ?
1712                     AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0);
1713             final int interrogatingPid = Binder.getCallingPid();
1714             final long identityToken = Binder.clearCallingIdentity();
1715             try {
1716                 connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId,
1717                         interactionId, callback, allFlags, interrogatingPid, interrogatingTid);
1718                 return getCompatibilityScale(resolvedWindowId);
1719             } catch (RemoteException re) {
1720                 if (DEBUG) {
1721                     Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
1722                 }
1723             } finally {
1724                 Binder.restoreCallingIdentity(identityToken);
1725             }
1726             return 0;
1727         }
1728 
1729         @Override
findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)1730         public float findFocus(int accessibilityWindowId, long accessibilityNodeId,
1731                 int focusType, int interactionId,
1732                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1733                 throws RemoteException {
1734             final int resolvedWindowId;
1735             IAccessibilityInteractionConnection connection = null;
1736             synchronized (mLock) {
1737                 final int resolvedUserId = mSecurityPolicy
1738                         .resolveCallingUserIdEnforcingPermissionsLocked(
1739                         UserHandle.getCallingUserId());
1740                 if (resolvedUserId != mCurrentUserId) {
1741                     return -1;
1742                 }
1743                 mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1744                 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1745                 final boolean permissionGranted =
1746                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
1747                 if (!permissionGranted) {
1748                     return 0;
1749                 } else {
1750                     connection = getConnectionLocked(resolvedWindowId);
1751                     if (connection == null) {
1752                         return 0;
1753                     }
1754                 }
1755             }
1756             final int flags = (mIncludeNotImportantViews) ?
1757                     AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1758             final int interrogatingPid = Binder.getCallingPid();
1759             final long identityToken = Binder.clearCallingIdentity();
1760             try {
1761                 connection.findFocus(accessibilityNodeId, focusType, interactionId, callback,
1762                         flags, interrogatingPid, interrogatingTid);
1763                 return getCompatibilityScale(resolvedWindowId);
1764             } catch (RemoteException re) {
1765                 if (DEBUG) {
1766                     Slog.e(LOG_TAG, "Error calling findAccessibilityFocus()");
1767                 }
1768             } finally {
1769                 Binder.restoreCallingIdentity(identityToken);
1770             }
1771             return 0;
1772         }
1773 
1774         @Override
focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)1775         public float focusSearch(int accessibilityWindowId, long accessibilityNodeId,
1776                 int direction, int interactionId,
1777                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1778                 throws RemoteException {
1779             final int resolvedWindowId;
1780             IAccessibilityInteractionConnection connection = null;
1781             synchronized (mLock) {
1782                 final int resolvedUserId = mSecurityPolicy
1783                         .resolveCallingUserIdEnforcingPermissionsLocked(
1784                         UserHandle.getCallingUserId());
1785                 if (resolvedUserId != mCurrentUserId) {
1786                     return -1;
1787                 }
1788                 mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1789                 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1790                 final boolean permissionGranted =
1791                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
1792                 if (!permissionGranted) {
1793                     return 0;
1794                 } else {
1795                     connection = getConnectionLocked(resolvedWindowId);
1796                     if (connection == null) {
1797                         return 0;
1798                     }
1799                 }
1800             }
1801             final int flags = (mIncludeNotImportantViews) ?
1802                     AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1803             final int interrogatingPid = Binder.getCallingPid();
1804             final long identityToken = Binder.clearCallingIdentity();
1805             try {
1806                 connection.focusSearch(accessibilityNodeId, direction, interactionId, callback,
1807                         flags, interrogatingPid, interrogatingTid);
1808                 return getCompatibilityScale(resolvedWindowId);
1809             } catch (RemoteException re) {
1810                 if (DEBUG) {
1811                     Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()");
1812                 }
1813             } finally {
1814                 Binder.restoreCallingIdentity(identityToken);
1815             }
1816             return 0;
1817         }
1818 
1819         @Override
performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)1820         public boolean performAccessibilityAction(int accessibilityWindowId,
1821                 long accessibilityNodeId, int action, Bundle arguments, int interactionId,
1822                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
1823                 throws RemoteException {
1824             final int resolvedWindowId;
1825             IAccessibilityInteractionConnection connection = null;
1826             synchronized (mLock) {
1827                 final int resolvedUserId = mSecurityPolicy
1828                         .resolveCallingUserIdEnforcingPermissionsLocked(
1829                         UserHandle.getCallingUserId());
1830                 if (resolvedUserId != mCurrentUserId) {
1831                     return false;
1832                 }
1833                 mSecurityPolicy.enforceCanRetrieveWindowContent(this);
1834                 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
1835                 final boolean permissionGranted = mSecurityPolicy.canPerformActionLocked(this,
1836                         resolvedWindowId, action, arguments);
1837                 if (!permissionGranted) {
1838                     return false;
1839                 } else {
1840                     connection = getConnectionLocked(resolvedWindowId);
1841                     if (connection == null) {
1842                         return false;
1843                     }
1844                 }
1845             }
1846             final int flags = (mIncludeNotImportantViews) ?
1847                     AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
1848             final int interrogatingPid = Binder.getCallingPid();
1849             final long identityToken = Binder.clearCallingIdentity();
1850             try {
1851                 connection.performAccessibilityAction(accessibilityNodeId, action, arguments,
1852                         interactionId, callback, flags, interrogatingPid, interrogatingTid);
1853             } catch (RemoteException re) {
1854                 if (DEBUG) {
1855                     Slog.e(LOG_TAG, "Error calling performAccessibilityAction()");
1856                 }
1857             } finally {
1858                 Binder.restoreCallingIdentity(identityToken);
1859             }
1860             return true;
1861         }
1862 
performGlobalAction(int action)1863         public boolean performGlobalAction(int action) {
1864             synchronized (mLock) {
1865                 final int resolvedUserId = mSecurityPolicy
1866                         .resolveCallingUserIdEnforcingPermissionsLocked(
1867                         UserHandle.getCallingUserId());
1868                 if (resolvedUserId != mCurrentUserId) {
1869                     return false;
1870                 }
1871             }
1872             final long identity = Binder.clearCallingIdentity();
1873             try {
1874                 switch (action) {
1875                     case AccessibilityService.GLOBAL_ACTION_BACK: {
1876                         sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK);
1877                     } return true;
1878                     case AccessibilityService.GLOBAL_ACTION_HOME: {
1879                         sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME);
1880                     } return true;
1881                     case AccessibilityService.GLOBAL_ACTION_RECENTS: {
1882                         openRecents();
1883                     } return true;
1884                     case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: {
1885                         expandNotifications();
1886                     } return true;
1887                     case AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS: {
1888                         expandQuickSettings();
1889                     } return true;
1890                 }
1891                 return false;
1892             } finally {
1893                 Binder.restoreCallingIdentity(identity);
1894             }
1895         }
1896 
onServiceDisconnected(ComponentName componentName)1897         public void onServiceDisconnected(ComponentName componentName) {
1898             /* do nothing - #binderDied takes care */
1899         }
1900 
linkToOwnDeath()1901         public void linkToOwnDeath() throws RemoteException {
1902             mService.linkToDeath(this, 0);
1903         }
1904 
unlinkToOwnDeath()1905         public void unlinkToOwnDeath() {
1906             mService.unlinkToDeath(this, 0);
1907         }
1908 
dispose()1909         public void dispose() {
1910             try {
1911                 // Clear the proxy in the other process so this
1912                 // IAccessibilityServiceConnection can be garbage collected.
1913                 mServiceInterface.setConnection(null, mId);
1914             } catch (RemoteException re) {
1915                 /* ignore */
1916             }
1917             mService = null;
1918             mServiceInterface = null;
1919         }
1920 
binderDied()1921         public void binderDied() {
1922             synchronized (mLock) {
1923                 // The death recipient is unregistered in tryRemoveServiceLocked
1924                 tryRemoveServiceLocked(this);
1925                 // We no longer have an automation service, so restore
1926                 // the state based on values in the settings database.
1927                 if (mIsAutomation) {
1928                     mUiAutomationService = null;
1929                     recreateInternalStateLocked(getUserStateLocked(mUserId));
1930                 }
1931             }
1932         }
1933 
1934         /**
1935          * Performs a notification for an {@link AccessibilityEvent}.
1936          *
1937          * @param event The event.
1938          */
notifyAccessibilityEvent(AccessibilityEvent event)1939         public void notifyAccessibilityEvent(AccessibilityEvent event) {
1940             synchronized (mLock) {
1941                 final int eventType = event.getEventType();
1942                 // Make a copy since during dispatch it is possible the event to
1943                 // be modified to remove its source if the receiving service does
1944                 // not have permission to access the window content.
1945                 AccessibilityEvent newEvent = AccessibilityEvent.obtain(event);
1946                 AccessibilityEvent oldEvent = mPendingEvents.get(eventType);
1947                 mPendingEvents.put(eventType, newEvent);
1948 
1949                 final int what = eventType;
1950                 if (oldEvent != null) {
1951                     mHandler.removeMessages(what);
1952                     oldEvent.recycle();
1953                 }
1954 
1955                 Message message = mHandler.obtainMessage(what);
1956                 mHandler.sendMessageDelayed(message, mNotificationTimeout);
1957             }
1958         }
1959 
1960         /**
1961          * Notifies an accessibility service client for a scheduled event given the event type.
1962          *
1963          * @param eventType The type of the event to dispatch.
1964          */
notifyAccessibilityEventInternal(int eventType)1965         private void notifyAccessibilityEventInternal(int eventType) {
1966             IAccessibilityServiceClient listener;
1967             AccessibilityEvent event;
1968 
1969             synchronized (mLock) {
1970                 listener = mServiceInterface;
1971 
1972                 // If the service died/was disabled while the message for dispatching
1973                 // the accessibility event was propagating the listener may be null.
1974                 if (listener == null) {
1975                     return;
1976                 }
1977 
1978                 event = mPendingEvents.get(eventType);
1979 
1980                 // Check for null here because there is a concurrent scenario in which this
1981                 // happens: 1) A binder thread calls notifyAccessibilityServiceDelayedLocked
1982                 // which posts a message for dispatching an event. 2) The message is pulled
1983                 // from the queue by the handler on the service thread and the latter is
1984                 // just about to acquire the lock and call this method. 3) Now another binder
1985                 // thread acquires the lock calling notifyAccessibilityServiceDelayedLocked
1986                 // so the service thread waits for the lock; 4) The binder thread replaces
1987                 // the event with a more recent one (assume the same event type) and posts a
1988                 // dispatch request releasing the lock. 5) Now the main thread is unblocked and
1989                 // dispatches the event which is removed from the pending ones. 6) And ... now
1990                 // the service thread handles the last message posted by the last binder call
1991                 // but the event is already dispatched and hence looking it up in the pending
1992                 // ones yields null. This check is much simpler that keeping count for each
1993                 // event type of each service to catch such a scenario since only one message
1994                 // is processed at a time.
1995                 if (event == null) {
1996                     return;
1997                 }
1998 
1999                 mPendingEvents.remove(eventType);
2000                 if (mSecurityPolicy.canRetrieveWindowContent(this)) {
2001                     event.setConnectionId(mId);
2002                 } else {
2003                     event.setSource(null);
2004                 }
2005                 event.setSealed(true);
2006             }
2007 
2008             try {
2009                 listener.onAccessibilityEvent(event);
2010                 if (DEBUG) {
2011                     Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
2012                 }
2013             } catch (RemoteException re) {
2014                 Slog.e(LOG_TAG, "Error during sending " + event + " to " + listener, re);
2015             } finally {
2016                 event.recycle();
2017             }
2018         }
2019 
notifyGesture(int gestureId)2020         public void notifyGesture(int gestureId) {
2021             mHandler.obtainMessage(MSG_ON_GESTURE, gestureId, 0).sendToTarget();
2022         }
2023 
notifyGestureInternal(int gestureId)2024         private void notifyGestureInternal(int gestureId) {
2025             IAccessibilityServiceClient listener = mServiceInterface;
2026             if (listener != null) {
2027                 try {
2028                     listener.onGesture(gestureId);
2029                 } catch (RemoteException re) {
2030                     Slog.e(LOG_TAG, "Error during sending gesture " + gestureId
2031                             + " to " + mService, re);
2032                 }
2033             }
2034         }
2035 
sendDownAndUpKeyEvents(int keyCode)2036         private void sendDownAndUpKeyEvents(int keyCode) {
2037             final long token = Binder.clearCallingIdentity();
2038 
2039             // Inject down.
2040             final long downTime = SystemClock.uptimeMillis();
2041             KeyEvent down = KeyEvent.obtain(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
2042                     KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM,
2043                     InputDevice.SOURCE_KEYBOARD, null);
2044             InputManager.getInstance().injectInputEvent(down,
2045                     InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
2046             down.recycle();
2047 
2048             // Inject up.
2049             final long upTime = SystemClock.uptimeMillis();
2050             KeyEvent up = KeyEvent.obtain(downTime, upTime, KeyEvent.ACTION_UP, keyCode, 0, 0,
2051                     KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM,
2052                     InputDevice.SOURCE_KEYBOARD, null);
2053             InputManager.getInstance().injectInputEvent(up,
2054                     InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
2055             up.recycle();
2056 
2057             Binder.restoreCallingIdentity(token);
2058         }
2059 
expandNotifications()2060         private void expandNotifications() {
2061             final long token = Binder.clearCallingIdentity();
2062 
2063             StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService(
2064                     android.app.Service.STATUS_BAR_SERVICE);
2065             statusBarManager.expandNotificationsPanel();
2066 
2067             Binder.restoreCallingIdentity(token);
2068         }
2069 
expandQuickSettings()2070         private void expandQuickSettings() {
2071             final long token = Binder.clearCallingIdentity();
2072 
2073             StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService(
2074                     android.app.Service.STATUS_BAR_SERVICE);
2075             statusBarManager.expandSettingsPanel();
2076 
2077             Binder.restoreCallingIdentity(token);
2078         }
2079 
openRecents()2080         private void openRecents() {
2081             final long token = Binder.clearCallingIdentity();
2082 
2083             IStatusBarService statusBarService = IStatusBarService.Stub.asInterface(
2084                     ServiceManager.getService("statusbar"));
2085             try {
2086                 statusBarService.toggleRecentApps();
2087             } catch (RemoteException e) {
2088                 Slog.e(LOG_TAG, "Error toggling recent apps.");
2089             }
2090 
2091             Binder.restoreCallingIdentity(token);
2092         }
2093 
getConnectionLocked(int windowId)2094         private IAccessibilityInteractionConnection getConnectionLocked(int windowId) {
2095             if (DEBUG) {
2096                 Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
2097             }
2098             AccessibilityConnectionWrapper wrapper = mGlobalInteractionConnections.get(windowId);
2099             if (wrapper == null) {
2100                 wrapper = getCurrentUserStateLocked().mInteractionConnections.get(windowId);
2101             }
2102             if (wrapper != null && wrapper.mConnection != null) {
2103                 return wrapper.mConnection;
2104             }
2105             if (DEBUG) {
2106                 Slog.e(LOG_TAG, "No interaction connection to window: " + windowId);
2107             }
2108             return null;
2109         }
2110 
resolveAccessibilityWindowIdLocked(int accessibilityWindowId)2111         private int resolveAccessibilityWindowIdLocked(int accessibilityWindowId) {
2112             if (accessibilityWindowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) {
2113                 return mSecurityPolicy.mActiveWindowId;
2114             }
2115             return accessibilityWindowId;
2116         }
2117 
getCompatibilityScale(int windowId)2118         private float getCompatibilityScale(int windowId) {
2119             try {
2120                 IBinder windowToken = mGlobalWindowTokens.get(windowId);
2121                 if (windowToken != null) {
2122                     return mWindowManagerService.getWindowCompatibilityScale(windowToken);
2123                 }
2124                 windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId);
2125                 if (windowToken != null) {
2126                     return mWindowManagerService.getWindowCompatibilityScale(windowToken);
2127                 }
2128             } catch (RemoteException re) {
2129                 /* ignore */
2130             }
2131             return 1.0f;
2132         }
2133     }
2134 
2135     final class SecurityPolicy {
2136         private static final int VALID_ACTIONS =
2137             AccessibilityNodeInfo.ACTION_CLICK
2138             | AccessibilityNodeInfo.ACTION_LONG_CLICK
2139             | AccessibilityNodeInfo.ACTION_FOCUS
2140             | AccessibilityNodeInfo.ACTION_CLEAR_FOCUS
2141             | AccessibilityNodeInfo.ACTION_SELECT
2142             | AccessibilityNodeInfo.ACTION_CLEAR_SELECTION
2143             | AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS
2144             | AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS
2145             | AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
2146             | AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
2147             | AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT
2148             | AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT
2149             | AccessibilityNodeInfo.ACTION_SCROLL_FORWARD
2150             | AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD;
2151 
2152         private static final int RETRIEVAL_ALLOWING_EVENT_TYPES =
2153             AccessibilityEvent.TYPE_VIEW_CLICKED
2154             | AccessibilityEvent.TYPE_VIEW_FOCUSED
2155             | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
2156             | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
2157             | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED
2158             | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
2159             | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
2160             | AccessibilityEvent.TYPE_VIEW_SELECTED
2161             | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
2162             | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED
2163             | AccessibilityEvent.TYPE_VIEW_SCROLLED
2164             | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
2165             | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED;
2166 
2167         private int mActiveWindowId;
2168         private boolean mTouchInteractionInProgress;
2169 
canDispatchAccessibilityEvent(AccessibilityEvent event)2170         private boolean canDispatchAccessibilityEvent(AccessibilityEvent event) {
2171             final int eventType = event.getEventType();
2172             switch (eventType) {
2173                 // All events that are for changes in a global window
2174                 // state should *always* be dispatched.
2175                 case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
2176                 case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
2177                 // All events generated by the user touching the
2178                 // screen should *always* be dispatched.
2179                 case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START:
2180                 case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END:
2181                 case AccessibilityEvent.TYPE_GESTURE_DETECTION_START:
2182                 case AccessibilityEvent.TYPE_GESTURE_DETECTION_END:
2183                 case AccessibilityEvent.TYPE_TOUCH_INTERACTION_START:
2184                 case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END:
2185                 // These will change the active window, so dispatch.
2186                 case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
2187                 case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: {
2188                     return true;
2189                 }
2190                 // All events for changes in window content should be
2191                 // dispatched *only* if this window is the active one.
2192                 default:
2193                     return event.getWindowId() == mActiveWindowId;
2194             }
2195         }
2196 
updateEventSourceLocked(AccessibilityEvent event)2197         public void updateEventSourceLocked(AccessibilityEvent event) {
2198             if ((event.getEventType() & RETRIEVAL_ALLOWING_EVENT_TYPES) == 0) {
2199                 event.setSource(null);
2200             }
2201         }
2202 
updateActiveWindow(int windowId, int eventType)2203         public void updateActiveWindow(int windowId, int eventType) {
2204             // The active window is either the window that has input focus or
2205             // the window that the user is currently touching. If the user is
2206             // touching a window that does not have input focus as soon as the
2207             // the user stops touching that window the focused window becomes
2208             // the active one.
2209             switch (eventType) {
2210                 case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: {
2211                     if (getFocusedWindowId() == windowId) {
2212                         mActiveWindowId = windowId;
2213                     }
2214                 } break;
2215                 case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER: {
2216                     // Do not allow delayed hover events to confuse us
2217                     // which the active window is.
2218                     if (mTouchInteractionInProgress) {
2219                         mActiveWindowId = windowId;
2220                     }
2221                 } break;
2222             }
2223         }
2224 
onTouchInteractionStart()2225         public void onTouchInteractionStart() {
2226             mTouchInteractionInProgress = true;
2227         }
2228 
onTouchInteractionEnd()2229         public void onTouchInteractionEnd() {
2230             mTouchInteractionInProgress = false;
2231             // We want to set the active window to be current immediately
2232             // after the user has stopped touching the screen since if the
2233             // user types with the IME he should get a feedback for the
2234             // letter typed in the text view which is in the input focused
2235             // window. Note that we always deliver hover accessibility events
2236             // (they are a result of user touching the screen) so change of
2237             // the active window before all hover accessibility events from
2238             // the touched window are delivered is fine.
2239             mActiveWindowId = getFocusedWindowId();
2240         }
2241 
getRetrievalAllowingWindowLocked()2242         public int getRetrievalAllowingWindowLocked() {
2243             return mActiveWindowId;
2244         }
2245 
canGetAccessibilityNodeInfoLocked(Service service, int windowId)2246         public boolean canGetAccessibilityNodeInfoLocked(Service service, int windowId) {
2247             return canRetrieveWindowContent(service) && isRetrievalAllowingWindow(windowId);
2248         }
2249 
canPerformActionLocked(Service service, int windowId, int action, Bundle arguments)2250         public boolean canPerformActionLocked(Service service, int windowId, int action,
2251                 Bundle arguments) {
2252             return canRetrieveWindowContent(service)
2253                 && isRetrievalAllowingWindow(windowId)
2254                 && isActionPermitted(action);
2255         }
2256 
canRetrieveWindowContent(Service service)2257         public boolean canRetrieveWindowContent(Service service) {
2258             return service.mCanRetrieveScreenContent;
2259         }
2260 
enforceCanRetrieveWindowContent(Service service)2261         public void enforceCanRetrieveWindowContent(Service service) throws RemoteException {
2262             // This happens due to incorrect registration so make it apparent.
2263             if (!canRetrieveWindowContent(service)) {
2264                 Slog.e(LOG_TAG, "Accessibility serivce " + service.mComponentName + " does not " +
2265                         "declare android:canRetrieveWindowContent.");
2266                 throw new RemoteException();
2267             }
2268         }
2269 
resolveCallingUserIdEnforcingPermissionsLocked(int userId)2270         public int resolveCallingUserIdEnforcingPermissionsLocked(int userId) {
2271             final int callingUid = Binder.getCallingUid();
2272             if (callingUid == Process.SYSTEM_UID
2273                     || callingUid == Process.SHELL_UID) {
2274                 return mCurrentUserId;
2275             }
2276             final int callingUserId = UserHandle.getUserId(callingUid);
2277             if (callingUserId == userId) {
2278                 return userId;
2279             }
2280             if (!hasPermission(Manifest.permission.INTERACT_ACROSS_USERS)
2281                     && !hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) {
2282                 throw new SecurityException("Call from user " + callingUserId + " as user "
2283                         + userId + " without permission INTERACT_ACROSS_USERS or "
2284                         + "INTERACT_ACROSS_USERS_FULL not allowed.");
2285             }
2286             if (userId == UserHandle.USER_CURRENT
2287                     || userId == UserHandle.USER_CURRENT_OR_SELF) {
2288                 return mCurrentUserId;
2289             }
2290             throw new IllegalArgumentException("Calling user can be changed to only "
2291                     + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF.");
2292         }
2293 
isCallerInteractingAcrossUsers(int userId)2294         public boolean isCallerInteractingAcrossUsers(int userId) {
2295             final int callingUid = Binder.getCallingUid();
2296             return (Binder.getCallingPid() == android.os.Process.myPid()
2297                     || callingUid == Process.SHELL_UID
2298                     || userId == UserHandle.USER_CURRENT
2299                     || userId == UserHandle.USER_CURRENT_OR_SELF);
2300         }
2301 
isRetrievalAllowingWindow(int windowId)2302         private boolean isRetrievalAllowingWindow(int windowId) {
2303             return (mActiveWindowId == windowId);
2304         }
2305 
isActionPermitted(int action)2306         private boolean isActionPermitted(int action) {
2307              return (VALID_ACTIONS & action) != 0;
2308         }
2309 
enforceCallingPermission(String permission, String function)2310         private void enforceCallingPermission(String permission, String function) {
2311             if (OWN_PROCESS_ID == Binder.getCallingPid()) {
2312                 return;
2313             }
2314             if (!hasPermission(permission)) {
2315                 throw new SecurityException("You do not have " + permission
2316                         + " required to call " + function);
2317             }
2318         }
2319 
hasPermission(String permission)2320         private boolean hasPermission(String permission) {
2321             return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED;
2322         }
2323 
getFocusedWindowId()2324         private int getFocusedWindowId() {
2325             try {
2326                 // We call this only on window focus change or after touch
2327                 // exploration gesture end and the shown windows are not that
2328                 // many, so the linear look up is just fine.
2329                 IBinder token = mWindowManagerService.getFocusedWindowToken();
2330                 if (token != null) {
2331                     synchronized (mLock) {
2332                         int windowId = getFocusedWindowIdLocked(token, mGlobalWindowTokens);
2333                         if (windowId < 0) {
2334                             windowId = getFocusedWindowIdLocked(token,
2335                                     getCurrentUserStateLocked().mWindowTokens);
2336                         }
2337                         return windowId;
2338                     }
2339                 }
2340             } catch (RemoteException re) {
2341                 /* ignore */
2342             }
2343             return -1;
2344         }
2345 
getFocusedWindowIdLocked(IBinder token, SparseArray<IBinder> windows)2346         private int getFocusedWindowIdLocked(IBinder token, SparseArray<IBinder> windows) {
2347             final int windowCount = windows.size();
2348             for (int i = 0; i < windowCount; i++) {
2349                 if (windows.valueAt(i) == token) {
2350                     return windows.keyAt(i);
2351                 }
2352             }
2353             return -1;
2354         }
2355     }
2356 
2357     private class UserState {
2358         public final int mUserId;
2359 
2360         public final CopyOnWriteArrayList<Service> mServices = new CopyOnWriteArrayList<Service>();
2361 
2362         public final RemoteCallbackList<IAccessibilityManagerClient> mClients =
2363             new RemoteCallbackList<IAccessibilityManagerClient>();
2364 
2365         public final Map<ComponentName, Service> mComponentNameToServiceMap =
2366                 new HashMap<ComponentName, Service>();
2367 
2368         public final List<AccessibilityServiceInfo> mInstalledServices =
2369                 new ArrayList<AccessibilityServiceInfo>();
2370 
2371         public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
2372 
2373         public final Set<ComponentName> mTouchExplorationGrantedServices =
2374                 new HashSet<ComponentName>();
2375 
2376         public final SparseArray<AccessibilityConnectionWrapper>
2377                 mInteractionConnections =
2378                 new SparseArray<AccessibilityConnectionWrapper>();
2379 
2380         public final SparseArray<IBinder> mWindowTokens = new SparseArray<IBinder>();
2381 
2382         public int mHandledFeedbackTypes = 0;
2383 
2384         public boolean mIsAccessibilityEnabled;
2385         public boolean mIsTouchExplorationEnabled;
2386         public boolean mIsDisplayMagnificationEnabled;
2387 
UserState(int userId)2388         public UserState(int userId) {
2389             mUserId = userId;
2390         }
2391     }
2392 
2393     private class TempUserStateChangeMemento {
2394         public int mUserId = UserHandle.USER_NULL;
2395         public boolean mIsAccessibilityEnabled;
2396         public boolean mIsTouchExplorationEnabled;
2397         public boolean mIsDisplayMagnificationEnabled;
2398         public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
2399         public final Set<ComponentName> mTouchExplorationGrantedServices =
2400                 new HashSet<ComponentName>();
2401 
initialize(int userId, UserState userState)2402         public void initialize(int userId, UserState userState) {
2403             mUserId = userId;
2404             mIsAccessibilityEnabled = userState.mIsAccessibilityEnabled;
2405             mIsTouchExplorationEnabled = userState.mIsTouchExplorationEnabled;
2406             mIsDisplayMagnificationEnabled = userState.mIsDisplayMagnificationEnabled;
2407             mEnabledServices.clear();
2408             mEnabledServices.addAll(userState.mEnabledServices);
2409             mTouchExplorationGrantedServices.clear();
2410             mTouchExplorationGrantedServices.addAll(userState.mTouchExplorationGrantedServices);
2411         }
2412 
applyTo(UserState userState)2413         public void applyTo(UserState userState) {
2414             userState.mIsAccessibilityEnabled = mIsAccessibilityEnabled;
2415             userState.mIsTouchExplorationEnabled = mIsTouchExplorationEnabled;
2416             userState.mIsDisplayMagnificationEnabled = mIsDisplayMagnificationEnabled;
2417             userState.mEnabledServices.clear();
2418             userState.mEnabledServices.addAll(mEnabledServices);
2419             userState.mTouchExplorationGrantedServices.clear();
2420             userState.mTouchExplorationGrantedServices.addAll(mTouchExplorationGrantedServices);
2421         }
2422 
clear()2423         public void clear() {
2424             mUserId = UserHandle.USER_NULL;
2425             mIsAccessibilityEnabled = false;
2426             mIsTouchExplorationEnabled = false;
2427             mIsDisplayMagnificationEnabled = false;
2428             mEnabledServices.clear();
2429             mTouchExplorationGrantedServices.clear();
2430         }
2431     }
2432 
2433     private final class AccessibilityContentObserver extends ContentObserver {
2434 
2435         private final Uri mAccessibilityEnabledUri = Settings.Secure.getUriFor(
2436                 Settings.Secure.ACCESSIBILITY_ENABLED);
2437 
2438         private final Uri mTouchExplorationEnabledUri = Settings.Secure.getUriFor(
2439                 Settings.Secure.TOUCH_EXPLORATION_ENABLED);
2440 
2441         private final Uri mDisplayMagnificationEnabledUri = Settings.Secure.getUriFor(
2442                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
2443 
2444         private final Uri mEnabledAccessibilityServicesUri = Settings.Secure.getUriFor(
2445                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
2446 
2447         private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure
2448                 .getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
2449 
AccessibilityContentObserver(Handler handler)2450         public AccessibilityContentObserver(Handler handler) {
2451             super(handler);
2452         }
2453 
register(ContentResolver contentResolver)2454         public void register(ContentResolver contentResolver) {
2455             contentResolver.registerContentObserver(mAccessibilityEnabledUri,
2456                     false, this, UserHandle.USER_ALL);
2457             contentResolver.registerContentObserver(mTouchExplorationEnabledUri,
2458                     false, this, UserHandle.USER_ALL);
2459             contentResolver.registerContentObserver(mDisplayMagnificationEnabledUri,
2460                     false, this, UserHandle.USER_ALL);
2461             contentResolver.registerContentObserver(mEnabledAccessibilityServicesUri,
2462                     false, this, UserHandle.USER_ALL);
2463             contentResolver.registerContentObserver(
2464                     mTouchExplorationGrantedAccessibilityServicesUri,
2465                     false, this, UserHandle.USER_ALL);
2466         }
2467 
2468         @Override
onChange(boolean selfChange, Uri uri)2469         public void onChange(boolean selfChange, Uri uri) {
2470             if (mAccessibilityEnabledUri.equals(uri)) {
2471                 synchronized (mLock) {
2472                     // We will update when the automation service dies.
2473                     if (mUiAutomationService == null) {
2474                         UserState userState = getCurrentUserStateLocked();
2475                         handleAccessibilityEnabledSettingChangedLocked(userState);
2476                         performServiceManagementLocked(userState);
2477                         updateInputFilterLocked(userState);
2478                         scheduleSendStateToClientsLocked(userState);
2479                     }
2480                 }
2481             } else if (mTouchExplorationEnabledUri.equals(uri)) {
2482                 synchronized (mLock) {
2483                     // We will update when the automation service dies.
2484                     if (mUiAutomationService == null) {
2485                         UserState userState = getCurrentUserStateLocked();
2486                         handleTouchExplorationEnabledSettingChangedLocked(userState);
2487                         updateInputFilterLocked(userState);
2488                         scheduleSendStateToClientsLocked(userState);
2489                     }
2490                 }
2491             } else if (mDisplayMagnificationEnabledUri.equals(uri)) {
2492                 synchronized (mLock) {
2493                     // We will update when the automation service dies.
2494                     if (mUiAutomationService == null) {
2495                         UserState userState = getCurrentUserStateLocked();
2496                         handleDisplayMagnificationEnabledSettingChangedLocked(userState);
2497                         updateInputFilterLocked(userState);
2498                         scheduleSendStateToClientsLocked(userState);
2499                     }
2500                 }
2501             } else if (mEnabledAccessibilityServicesUri.equals(uri)) {
2502                 synchronized (mLock) {
2503                     // We will update when the automation service dies.
2504                     if (mUiAutomationService == null) {
2505                         UserState userState = getCurrentUserStateLocked();
2506                         populateEnabledAccessibilityServicesLocked(userState);
2507                         manageServicesLocked(userState);
2508                     }
2509                 }
2510             } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) {
2511                 synchronized (mLock) {
2512                     // We will update when the automation service dies.
2513                     if (mUiAutomationService == null) {
2514                         UserState userState = getCurrentUserStateLocked();
2515                         populateTouchExplorationGrantedAccessibilityServicesLocked(userState);
2516                         handleTouchExplorationGrantedAccessibilityServicesChangedLocked(userState);
2517                     }
2518                 }
2519             }
2520         }
2521     }
2522 }
2523