• 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.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED;
20 import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
21 import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
22 import static android.view.accessibility.AccessibilityManager.ShortcutType;
23 
24 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
25 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
26 import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
27 import static com.android.internal.accessibility.util.AccessibilityStatsLogUtils.logAccessibilityShortcutActivated;
28 import static com.android.internal.util.FunctionalUtils.ignoreRemoteException;
29 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
30 import static com.android.server.accessibility.AccessibilityUserState.doesShortcutTargetsStringContain;
31 
32 import android.Manifest;
33 import android.accessibilityservice.AccessibilityGestureEvent;
34 import android.accessibilityservice.AccessibilityService;
35 import android.accessibilityservice.AccessibilityServiceInfo;
36 import android.accessibilityservice.AccessibilityShortcutInfo;
37 import android.accessibilityservice.IAccessibilityServiceClient;
38 import android.annotation.NonNull;
39 import android.annotation.Nullable;
40 import android.app.ActivityOptions;
41 import android.app.AlertDialog;
42 import android.app.PendingIntent;
43 import android.app.RemoteAction;
44 import android.appwidget.AppWidgetManagerInternal;
45 import android.content.ActivityNotFoundException;
46 import android.content.BroadcastReceiver;
47 import android.content.ComponentName;
48 import android.content.ContentResolver;
49 import android.content.Context;
50 import android.content.DialogInterface;
51 import android.content.DialogInterface.OnClickListener;
52 import android.content.Intent;
53 import android.content.IntentFilter;
54 import android.content.pm.PackageManager;
55 import android.content.pm.PackageManagerInternal;
56 import android.content.pm.ResolveInfo;
57 import android.content.pm.ServiceInfo;
58 import android.database.ContentObserver;
59 import android.graphics.Point;
60 import android.graphics.Rect;
61 import android.graphics.Region;
62 import android.hardware.display.DisplayManager;
63 import android.hardware.fingerprint.IFingerprintService;
64 import android.media.AudioManagerInternal;
65 import android.net.Uri;
66 import android.os.Binder;
67 import android.os.Build;
68 import android.os.Bundle;
69 import android.os.Handler;
70 import android.os.IBinder;
71 import android.os.Looper;
72 import android.os.Message;
73 import android.os.PowerManager;
74 import android.os.Process;
75 import android.os.RemoteCallbackList;
76 import android.os.RemoteException;
77 import android.os.ResultReceiver;
78 import android.os.ServiceManager;
79 import android.os.ShellCallback;
80 import android.os.SystemClock;
81 import android.os.UserHandle;
82 import android.os.UserManager;
83 import android.provider.Settings;
84 import android.provider.SettingsStringUtil.SettingStringHelper;
85 import android.text.TextUtils;
86 import android.text.TextUtils.SimpleStringSplitter;
87 import android.util.ArraySet;
88 import android.util.IntArray;
89 import android.util.Slog;
90 import android.util.SparseArray;
91 import android.view.Display;
92 import android.view.IWindow;
93 import android.view.KeyEvent;
94 import android.view.MagnificationSpec;
95 import android.view.WindowManager;
96 import android.view.accessibility.AccessibilityEvent;
97 import android.view.accessibility.AccessibilityInteractionClient;
98 import android.view.accessibility.AccessibilityManager;
99 import android.view.accessibility.AccessibilityNodeInfo;
100 import android.view.accessibility.AccessibilityWindowInfo;
101 import android.view.accessibility.IAccessibilityInteractionConnection;
102 import android.view.accessibility.IAccessibilityManager;
103 import android.view.accessibility.IAccessibilityManagerClient;
104 import android.view.accessibility.IWindowMagnificationConnection;
105 
106 import com.android.internal.R;
107 import com.android.internal.accessibility.AccessibilityShortcutController;
108 import com.android.internal.accessibility.AccessibilityShortcutController.ToggleableFrameworkFeatureInfo;
109 import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity;
110 import com.android.internal.accessibility.dialog.AccessibilityShortcutChooserActivity;
111 import com.android.internal.annotations.GuardedBy;
112 import com.android.internal.annotations.VisibleForTesting;
113 import com.android.internal.content.PackageMonitor;
114 import com.android.internal.os.BackgroundThread;
115 import com.android.internal.util.ArrayUtils;
116 import com.android.internal.util.DumpUtils;
117 import com.android.internal.util.IntPair;
118 import com.android.server.LocalServices;
119 import com.android.server.SystemService;
120 import com.android.server.accessibility.magnification.FullScreenMagnificationController;
121 import com.android.server.accessibility.magnification.MagnificationController;
122 import com.android.server.accessibility.magnification.WindowMagnificationManager;
123 import com.android.server.pm.UserManagerInternal;
124 import com.android.server.wm.ActivityTaskManagerInternal;
125 import com.android.server.wm.WindowManagerInternal;
126 
127 import org.xmlpull.v1.XmlPullParserException;
128 
129 import java.io.FileDescriptor;
130 import java.io.IOException;
131 import java.io.PrintWriter;
132 import java.util.ArrayList;
133 import java.util.Arrays;
134 import java.util.Collections;
135 import java.util.HashSet;
136 import java.util.Iterator;
137 import java.util.List;
138 import java.util.Map;
139 import java.util.Set;
140 import java.util.function.Consumer;
141 import java.util.function.Function;
142 import java.util.function.Predicate;
143 
144 /**
145  * This class is instantiated by the system as a system level service and can be
146  * accessed only by the system. The task of this service is to be a centralized
147  * event dispatch for {@link AccessibilityEvent}s generated across all processes
148  * on the device. Events are dispatched to {@link AccessibilityService}s.
149  */
150 public class AccessibilityManagerService extends IAccessibilityManager.Stub
151         implements AbstractAccessibilityServiceConnection.SystemSupport,
152         AccessibilityUserState.ServiceInfoChangeListener,
153         AccessibilityWindowManager.AccessibilityEventSender,
154         AccessibilitySecurityPolicy.AccessibilityUserManager,
155         SystemActionPerformer.SystemActionsChangedListener {
156 
157     private static final boolean DEBUG = false;
158 
159     private static final String LOG_TAG = "AccessibilityManagerService";
160 
161     // TODO: This is arbitrary. When there is time implement this by watching
162     //       when that accessibility services are bound.
163     private static final int WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS = 3000;
164 
165     // TODO: Restructure service initialization so services aren't connected before all of
166     //       their capabilities are ready.
167     private static final int WAIT_MOTION_INJECTOR_TIMEOUT_MILLIS = 1000;
168 
169     private static final String FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE =
170         "registerUiTestAutomationService";
171 
172     private static final String TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED =
173             "temporaryEnableAccessibilityStateUntilKeyguardRemoved";
174 
175     private static final String GET_WINDOW_TOKEN = "getWindowToken";
176 
177     private static final String SET_PIP_ACTION_REPLACEMENT =
178             "setPictureInPictureActionReplacingConnection";
179 
180     private static final char COMPONENT_NAME_SEPARATOR = ':';
181 
182     private static final int OWN_PROCESS_ID = android.os.Process.myPid();
183 
184     // Each service has an ID. Also provide one for magnification gesture handling
185     public static final int MAGNIFICATION_GESTURE_HANDLER_ID = 0;
186 
187     private static int sIdCounter = MAGNIFICATION_GESTURE_HANDLER_ID + 1;
188 
189     private final Context mContext;
190 
191     private final Object mLock = new Object();
192 
193     private final SimpleStringSplitter mStringColonSplitter =
194             new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
195 
196     private final Rect mTempRect = new Rect();
197     private final Rect mTempRect1 = new Rect();
198 
199     private final PackageManager mPackageManager;
200 
201     private final PowerManager mPowerManager;
202 
203     private final WindowManagerInternal mWindowManagerService;
204 
205     private final AccessibilitySecurityPolicy mSecurityPolicy;
206 
207     private final AccessibilityWindowManager mA11yWindowManager;
208 
209     private final AccessibilityDisplayListener mA11yDisplayListener;
210 
211     private final ActivityTaskManagerInternal mActivityTaskManagerService;
212 
213     private final MainHandler mMainHandler;
214 
215     // Lazily initialized - access through getSystemActionPerfomer()
216     private SystemActionPerformer mSystemActionPerformer;
217 
218     private InteractionBridge mInteractionBridge;
219 
220     private AlertDialog mEnableTouchExplorationDialog;
221 
222     private AccessibilityInputFilter mInputFilter;
223 
224     private boolean mHasInputFilter;
225 
226     private KeyEventDispatcher mKeyEventDispatcher;
227 
228     private SparseArray<MotionEventInjector> mMotionEventInjectors;
229 
230     private FingerprintGestureDispatcher mFingerprintGestureDispatcher;
231 
232     private final Set<ComponentName> mTempComponentNameSet = new HashSet<>();
233 
234     private final List<AccessibilityServiceInfo> mTempAccessibilityServiceInfoList =
235             new ArrayList<>();
236 
237     private final IntArray mTempIntArray = new IntArray(0);
238 
239     private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients =
240             new RemoteCallbackList<>();
241 
242     @VisibleForTesting
243     final SparseArray<AccessibilityUserState> mUserStates = new SparseArray<>();
244 
245     private final UiAutomationManager mUiAutomationManager = new UiAutomationManager(mLock);
246     private final AccessibilityTraceManager mTraceManager;
247 
248     private int mCurrentUserId = UserHandle.USER_SYSTEM;
249 
250     //TODO: Remove this hack
251     private boolean mInitialized;
252 
253     private Point mTempPoint = new Point();
254     private boolean mIsAccessibilityButtonShown;
255     private MagnificationController mMagnificationController;
256 
getCurrentUserStateLocked()257     private AccessibilityUserState getCurrentUserStateLocked() {
258         return getUserStateLocked(mCurrentUserId);
259     }
260 
261     public static final class Lifecycle extends SystemService {
262         private final AccessibilityManagerService mService;
263 
Lifecycle(Context context)264         public Lifecycle(Context context) {
265             super(context);
266             mService = new AccessibilityManagerService(context);
267         }
268 
269         @Override
onStart()270         public void onStart() {
271             publishBinderService(Context.ACCESSIBILITY_SERVICE, mService);
272         }
273 
274         @Override
onBootPhase(int phase)275         public void onBootPhase(int phase) {
276             mService.onBootPhase(phase);
277         }
278     }
279 
280     @VisibleForTesting
AccessibilityManagerService( Context context, PackageManager packageManager, AccessibilitySecurityPolicy securityPolicy, SystemActionPerformer systemActionPerformer, AccessibilityWindowManager a11yWindowManager, AccessibilityDisplayListener a11yDisplayListener, MagnificationController magnificationController)281     AccessibilityManagerService(
282             Context context,
283             PackageManager packageManager,
284             AccessibilitySecurityPolicy securityPolicy,
285             SystemActionPerformer systemActionPerformer,
286             AccessibilityWindowManager a11yWindowManager,
287             AccessibilityDisplayListener a11yDisplayListener,
288             MagnificationController magnificationController) {
289         mContext = context;
290         mPowerManager =  (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
291         mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
292         mTraceManager = new AccessibilityTraceManager(
293                 mWindowManagerService.getAccessibilityController(), this);
294         mMainHandler = new MainHandler(mContext.getMainLooper());
295         mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
296         mPackageManager = packageManager;
297         mSecurityPolicy = securityPolicy;
298         mSystemActionPerformer = systemActionPerformer;
299         mA11yWindowManager = a11yWindowManager;
300         mA11yDisplayListener = a11yDisplayListener;
301         mMagnificationController = magnificationController;
302         init();
303     }
304 
305     /**
306      * Creates a new instance.
307      *
308      * @param context A {@link Context} instance.
309      */
AccessibilityManagerService(Context context)310     public AccessibilityManagerService(Context context) {
311         mContext = context;
312         mPowerManager = context.getSystemService(PowerManager.class);
313         mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
314         mTraceManager = new AccessibilityTraceManager(
315                 mWindowManagerService.getAccessibilityController(), this);
316         mMainHandler = new MainHandler(mContext.getMainLooper());
317         mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
318         mPackageManager = mContext.getPackageManager();
319         PolicyWarningUIController policyWarningUIController;
320         if (AccessibilitySecurityPolicy.POLICY_WARNING_ENABLED) {
321             policyWarningUIController = new PolicyWarningUIController(mMainHandler, context,
322                     new PolicyWarningUIController.NotificationController(context));
323         }
324         mSecurityPolicy = new AccessibilitySecurityPolicy(policyWarningUIController, mContext,
325                 this);
326         mA11yWindowManager = new AccessibilityWindowManager(mLock, mMainHandler,
327                 mWindowManagerService, this, mSecurityPolicy, this);
328         mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler);
329         mMagnificationController = new MagnificationController(this, mLock, mContext);
330         init();
331     }
332 
init()333     private void init() {
334         mSecurityPolicy.setAccessibilityWindowManager(mA11yWindowManager);
335         registerBroadcastReceivers();
336         new AccessibilityContentObserver(mMainHandler).register(
337                 mContext.getContentResolver());
338     }
339 
340     @Override
getCurrentUserIdLocked()341     public int getCurrentUserIdLocked() {
342         if (mTraceManager.isA11yTracingEnabled()) {
343             mTraceManager.logTrace(LOG_TAG + ".getCurrentUserIdLocked");
344         }
345         return mCurrentUserId;
346     }
347 
348     @Override
isAccessibilityButtonShown()349     public boolean isAccessibilityButtonShown() {
350         if (mTraceManager.isA11yTracingEnabled()) {
351             mTraceManager.logTrace(LOG_TAG + ".isAccessibilityButtonShown");
352         }
353         return mIsAccessibilityButtonShown;
354     }
355 
356     @Override
onServiceInfoChangedLocked(AccessibilityUserState userState)357     public void onServiceInfoChangedLocked(AccessibilityUserState userState) {
358         if (mTraceManager.isA11yTracingEnabled()) {
359             mTraceManager.logTrace(
360                     LOG_TAG + ".onServiceInfoChangedLocked", "userState=" + userState);
361         }
362         mSecurityPolicy.onBoundServicesChangedLocked(userState.mUserId,
363                 userState.mBoundServices);
364         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
365     }
366 
367     @Nullable
getFingerprintGestureDispatcher()368     public FingerprintGestureDispatcher getFingerprintGestureDispatcher() {
369         return mFingerprintGestureDispatcher;
370     }
371 
onBootPhase(int phase)372     private void onBootPhase(int phase) {
373         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
374             if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
375                 mSecurityPolicy.setAppWidgetManager(
376                         LocalServices.getService(AppWidgetManagerInternal.class));
377             }
378         }
379     }
380 
getCurrentUserState()381     AccessibilityUserState getCurrentUserState() {
382         synchronized (mLock) {
383             return getCurrentUserStateLocked();
384         }
385     }
386 
getUserState(int userId)387     private AccessibilityUserState getUserState(int userId) {
388         synchronized (mLock) {
389             return getUserStateLocked(userId);
390         }
391     }
392 
393     @NonNull
getUserStateLocked(int userId)394     private AccessibilityUserState getUserStateLocked(int userId) {
395         AccessibilityUserState state = mUserStates.get(userId);
396         if (state == null) {
397             state = new AccessibilityUserState(userId, mContext, this);
398             mUserStates.put(userId, state);
399         }
400         return state;
401     }
402 
getBindInstantServiceAllowed(int userId)403     boolean getBindInstantServiceAllowed(int userId) {
404         synchronized (mLock) {
405             final AccessibilityUserState userState = getUserStateLocked(userId);
406             return userState.getBindInstantServiceAllowedLocked();
407         }
408     }
409 
setBindInstantServiceAllowed(int userId, boolean allowed)410     void setBindInstantServiceAllowed(int userId, boolean allowed) {
411         mContext.enforceCallingOrSelfPermission(
412                 Manifest.permission.MANAGE_BIND_INSTANT_SERVICE,
413                 "setBindInstantServiceAllowed");
414         synchronized (mLock) {
415             final AccessibilityUserState userState = getUserStateLocked(userId);
416             if (allowed != userState.getBindInstantServiceAllowedLocked()) {
417                 userState.setBindInstantServiceAllowedLocked(allowed);
418                 onUserStateChangedLocked(userState);
419             }
420         }
421     }
422 
registerBroadcastReceivers()423     private void registerBroadcastReceivers() {
424         PackageMonitor monitor = new PackageMonitor() {
425             @Override
426             public void onSomePackagesChanged() {
427                 if (mTraceManager.isA11yTracingEnabled()) {
428                     mTraceManager.logTrace(LOG_TAG + ".PM.onSomePackagesChanged");
429                 }
430 
431                 synchronized (mLock) {
432                     // Only the profile parent can install accessibility services.
433                     // Therefore we ignore packages from linked profiles.
434                     if (getChangingUserId() != mCurrentUserId) {
435                         return;
436                     }
437                     // We will update when the automation service dies.
438                     final AccessibilityUserState userState = getCurrentUserStateLocked();
439                     // We have to reload the installed services since some services may
440                     // have different attributes, resolve info (does not support equals),
441                     // etc. Remove them then to force reload.
442                     userState.mInstalledServices.clear();
443                     if (readConfigurationForUserStateLocked(userState)) {
444                         onUserStateChangedLocked(userState);
445                     }
446                 }
447             }
448 
449             @Override
450             public void onPackageUpdateFinished(String packageName, int uid) {
451                 // The package should already be removed from mBoundServices, and added into
452                 // mBindingServices in binderDied() during updating. Remove services from  this
453                 // package from mBindingServices, and then update the user state to re-bind new
454                 // versions of them.
455                 if (mTraceManager.isA11yTracingEnabled()) {
456                     mTraceManager.logTrace(LOG_TAG + ".PM.onPackageUpdateFinished",
457                             "packageName=" + packageName + ";uid=" + uid);
458                 }
459                 synchronized (mLock) {
460                     final int userId = getChangingUserId();
461                     if (userId != mCurrentUserId) {
462                         return;
463                     }
464                     final AccessibilityUserState userState = getUserStateLocked(userId);
465                     final boolean reboundAService = userState.getBindingServicesLocked().removeIf(
466                             component -> component != null
467                                     && component.getPackageName().equals(packageName))
468                             || userState.mCrashedServices.removeIf(component -> component != null
469                                     && component.getPackageName().equals(packageName));
470                     // Reloads the installed services info to make sure the rebound service could
471                     // get a new one.
472                     userState.mInstalledServices.clear();
473                     final boolean configurationChanged =
474                             readConfigurationForUserStateLocked(userState);
475                     if (reboundAService || configurationChanged) {
476                         onUserStateChangedLocked(userState);
477                     }
478                     // Passing 0 for restoreFromSdkInt to have this migration check execute each
479                     // time. It can make sure a11y button settings are correctly if there's an a11y
480                     // service updated and modifies the a11y button configuration.
481                     migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, packageName,
482                             /* restoreFromSdkInt = */0);
483                 }
484             }
485 
486             @Override
487             public void onPackageRemoved(String packageName, int uid) {
488                 if (mTraceManager.isA11yTracingEnabled()) {
489                     mTraceManager.logTrace(LOG_TAG + ".PM.onPackageRemoved",
490                             "packageName=" + packageName + ";uid=" + uid);
491                 }
492 
493                 synchronized (mLock) {
494                     final int userId = getChangingUserId();
495                     // Only the profile parent can install accessibility services.
496                     // Therefore we ignore packages from linked profiles.
497                     if (userId != mCurrentUserId) {
498                         return;
499                     }
500                     final AccessibilityUserState userState = getUserStateLocked(userId);
501                     final Predicate<ComponentName> filter =
502                             component -> component != null && component.getPackageName().equals(
503                                     packageName);
504                     userState.mBindingServices.removeIf(filter);
505                     userState.mCrashedServices.removeIf(filter);
506                     final Iterator<ComponentName> it = userState.mEnabledServices.iterator();
507                     while (it.hasNext()) {
508                         final ComponentName comp = it.next();
509                         final String compPkg = comp.getPackageName();
510                         if (compPkg.equals(packageName)) {
511                             it.remove();
512                             // Update the enabled services setting.
513                             persistComponentNamesToSettingLocked(
514                                     Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
515                                     userState.mEnabledServices, userId);
516                             // Update the touch exploration granted services setting.
517                             userState.mTouchExplorationGrantedServices.remove(comp);
518                             persistComponentNamesToSettingLocked(
519                                     Settings.Secure.
520                                     TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
521                                     userState.mTouchExplorationGrantedServices, userId);
522                             onUserStateChangedLocked(userState);
523                             return;
524                         }
525                     }
526                 }
527             }
528 
529             @Override
530             public boolean onHandleForceStop(Intent intent, String[] packages,
531                     int uid, boolean doit) {
532                 if (mTraceManager.isA11yTracingEnabled()) {
533                     mTraceManager.logTrace(LOG_TAG + ".PM.onHandleForceStop",
534                             "intent=" + intent + ";packages=" + packages + ";uid=" + uid
535                             + ";doit=" + doit);
536                 }
537                 synchronized (mLock) {
538                     final int userId = getChangingUserId();
539                     // Only the profile parent can install accessibility services.
540                     // Therefore we ignore packages from linked profiles.
541                     if (userId != mCurrentUserId) {
542                         return false;
543                     }
544                     final AccessibilityUserState userState = getUserStateLocked(userId);
545                     final Iterator<ComponentName> it = userState.mEnabledServices.iterator();
546                     while (it.hasNext()) {
547                         final ComponentName comp = it.next();
548                         final String compPkg = comp.getPackageName();
549                         for (String pkg : packages) {
550                             if (compPkg.equals(pkg)) {
551                                 if (!doit) {
552                                     return true;
553                                 }
554                                 it.remove();
555                                 userState.getBindingServicesLocked().remove(comp);
556                                 userState.getCrashedServicesLocked().remove(comp);
557                                 persistComponentNamesToSettingLocked(
558                                         Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
559                                         userState.mEnabledServices, userId);
560                                 onUserStateChangedLocked(userState);
561                             }
562                         }
563                     }
564                     return false;
565                 }
566             }
567         };
568 
569         // package changes
570         monitor.register(mContext, null,  UserHandle.ALL, true);
571 
572         // user change and unlock
573         IntentFilter intentFilter = new IntentFilter();
574         intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
575         intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
576         intentFilter.addAction(Intent.ACTION_USER_REMOVED);
577         intentFilter.addAction(Intent.ACTION_USER_PRESENT);
578         intentFilter.addAction(Intent.ACTION_SETTING_RESTORED);
579 
580         mContext.registerReceiverAsUser(new BroadcastReceiver() {
581             @Override
582             public void onReceive(Context context, Intent intent) {
583                 if (mTraceManager.isA11yTracingEnabled()) {
584                     mTraceManager.logTrace(LOG_TAG + ".BR.onReceive",
585                             "context=" + context + ";intent=" + intent);
586                 }
587 
588                 String action = intent.getAction();
589                 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
590                     switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
591                 } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
592                     unlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
593                 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
594                     removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
595                 } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
596                     // We will update when the automation service dies.
597                     synchronized (mLock) {
598                         AccessibilityUserState userState = getCurrentUserStateLocked();
599                         if (readConfigurationForUserStateLocked(userState)) {
600                             onUserStateChangedLocked(userState);
601                         }
602                     }
603                 } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) {
604                     final String which = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
605                     if (Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES.equals(which)) {
606                         synchronized (mLock) {
607                             restoreEnabledAccessibilityServicesLocked(
608                                     intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE),
609                                     intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE),
610                                     intent.getIntExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT,
611                                             0));
612                         }
613                     } else if (ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED.equals(which)) {
614                         synchronized (mLock) {
615                             restoreLegacyDisplayMagnificationNavBarIfNeededLocked(
616                                     intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE),
617                                     intent.getIntExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT,
618                                             0));
619                         }
620                     } else if (Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS.equals(which)) {
621                         synchronized (mLock) {
622                             restoreAccessibilityButtonTargetsLocked(
623                                     intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE),
624                                     intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE));
625                         }
626                     }
627                 }
628             }
629         }, UserHandle.ALL, intentFilter, null, null);
630     }
631 
632     // Called only during settings restore; currently supports only the owner user
633     // TODO: b/22388012
restoreLegacyDisplayMagnificationNavBarIfNeededLocked(String newSetting, int restoreFromSdkInt)634     private void restoreLegacyDisplayMagnificationNavBarIfNeededLocked(String newSetting,
635             int restoreFromSdkInt) {
636         if (restoreFromSdkInt >= Build.VERSION_CODES.R) {
637             return;
638         }
639 
640         boolean displayMagnificationNavBarEnabled;
641         try {
642             displayMagnificationNavBarEnabled = Integer.parseInt(newSetting) == 1;
643         } catch (NumberFormatException e) {
644             Slog.w(LOG_TAG, "number format is incorrect" + e);
645             return;
646         }
647 
648         final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM);
649         final Set<String> targetsFromSetting = new ArraySet<>();
650         readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
651                 userState.mUserId, str -> str, targetsFromSetting);
652         final boolean targetsContainMagnification = targetsFromSetting.contains(
653                 MAGNIFICATION_CONTROLLER_NAME);
654         if (targetsContainMagnification == displayMagnificationNavBarEnabled) {
655             return;
656         }
657 
658         if (displayMagnificationNavBarEnabled) {
659             targetsFromSetting.add(MAGNIFICATION_CONTROLLER_NAME);
660         } else {
661             targetsFromSetting.remove(MAGNIFICATION_CONTROLLER_NAME);
662         }
663         persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
664                 userState.mUserId, targetsFromSetting, str -> str);
665         readAccessibilityButtonTargetsLocked(userState);
666         onUserStateChangedLocked(userState);
667     }
668 
669     @Override
addClient(IAccessibilityManagerClient callback, int userId)670     public long addClient(IAccessibilityManagerClient callback, int userId) {
671         if (mTraceManager.isA11yTracingEnabled()) {
672             mTraceManager.logTrace(LOG_TAG + ".addClient",
673                     "callback=" + callback + ";userId=" + userId);
674         }
675 
676         synchronized (mLock) {
677             // We treat calls from a profile as if made by its parent as profiles
678             // share the accessibility state of the parent. The call below
679             // performs the current profile parent resolution.
680             final int resolvedUserId = mSecurityPolicy
681                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
682 
683             // If the client is from a process that runs across users such as
684             // the system UI or the system we add it to the global state that
685             // is shared across users.
686             AccessibilityUserState userState = getUserStateLocked(resolvedUserId);
687             Client client = new Client(callback, Binder.getCallingUid(), userState);
688             if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
689                 mGlobalClients.register(callback, client);
690                 if (DEBUG) {
691                     Slog.i(LOG_TAG, "Added global client for pid:" + Binder.getCallingPid());
692                 }
693                 return IntPair.of(
694                         getClientStateLocked(userState),
695                         client.mLastSentRelevantEventTypes);
696             } else {
697                 userState.mUserClients.register(callback, client);
698                 // If this client is not for the current user we do not
699                 // return a state since it is not for the foreground user.
700                 // We will send the state to the client on a user switch.
701                 if (DEBUG) {
702                     Slog.i(LOG_TAG, "Added user client for pid:" + Binder.getCallingPid()
703                             + " and userId:" + mCurrentUserId);
704                 }
705                 return IntPair.of(
706                         (resolvedUserId == mCurrentUserId) ? getClientStateLocked(userState) : 0,
707                         client.mLastSentRelevantEventTypes);
708             }
709         }
710     }
711 
712     @Override
removeClient(IAccessibilityManagerClient callback, int userId)713     public boolean removeClient(IAccessibilityManagerClient callback, int userId) {
714         // TODO(b/190216606): Add tracing for removeClient when implementation is the same in master
715 
716         synchronized (mLock) {
717             final int resolvedUserId = mSecurityPolicy
718                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
719 
720             AccessibilityUserState userState = getUserStateLocked(resolvedUserId);
721             if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
722                 boolean unregistered = mGlobalClients.unregister(callback);
723                 if (DEBUG) {
724                     Slog.i(LOG_TAG,
725                             "Removed global client for pid:" + Binder.getCallingPid() + "state: "
726                                     + unregistered);
727                 }
728                 return unregistered;
729             } else {
730                 boolean unregistered = userState.mUserClients.unregister(callback);
731                 if (DEBUG) {
732                     Slog.i(LOG_TAG, "Removed user client for pid:" + Binder.getCallingPid()
733                             + " and userId:" + resolvedUserId + "state: " + unregistered);
734                 }
735                 return unregistered;
736             }
737         }
738     }
739 
740     @Override
sendAccessibilityEvent(AccessibilityEvent event, int userId)741     public void sendAccessibilityEvent(AccessibilityEvent event, int userId) {
742         if (mTraceManager.isA11yTracingEnabled()) {
743             mTraceManager.logTrace(LOG_TAG + ".sendAccessibilityEvent",
744                     "event=" + event + ";userId=" + userId);
745         }
746         boolean dispatchEvent = false;
747 
748         synchronized (mLock) {
749             if (event.getWindowId() ==
750                 AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID) {
751                 // The replacer window isn't shown to services. Move its events into the pip.
752                 AccessibilityWindowInfo pip = mA11yWindowManager.getPictureInPictureWindowLocked();
753                 if (pip != null) {
754                     int pipId = pip.getId();
755                     event.setWindowId(pipId);
756                 }
757             }
758 
759             // We treat calls from a profile as if made by its parent as profiles
760             // share the accessibility state of the parent. The call below
761             // performs the current profile parent resolution.
762             final int resolvedUserId = mSecurityPolicy
763                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
764 
765             // Make sure the reported package is one the caller has access to.
766             event.setPackageName(mSecurityPolicy.resolveValidReportedPackageLocked(
767                     event.getPackageName(), UserHandle.getCallingAppId(), resolvedUserId,
768                     getCallingPid()));
769 
770             // This method does nothing for a background user.
771             if (resolvedUserId == mCurrentUserId) {
772                 if (mSecurityPolicy.canDispatchAccessibilityEventLocked(mCurrentUserId, event)) {
773                     mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(
774                             mCurrentUserId, event.getWindowId(), event.getSourceNodeId(),
775                             event.getEventType(), event.getAction());
776                     mSecurityPolicy.updateEventSourceLocked(event);
777                     dispatchEvent = true;
778                 }
779                 if (mHasInputFilter && mInputFilter != null) {
780                     mMainHandler.sendMessage(obtainMessage(
781                             AccessibilityManagerService::sendAccessibilityEventToInputFilter,
782                             this, AccessibilityEvent.obtain(event)));
783                 }
784             }
785         }
786 
787         if (dispatchEvent) {
788             // Make sure clients receiving this event will be able to get the
789             // current state of the windows as the window manager may be delaying
790             // the computation for performance reasons.
791             boolean shouldComputeWindows = false;
792             int displayId = Display.INVALID_DISPLAY;
793             synchronized (mLock) {
794                 final int windowId = event.getWindowId();
795                 if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
796                         && windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
797                     displayId = mA11yWindowManager.getDisplayIdByUserIdAndWindowIdLocked(
798                             mCurrentUserId, windowId);
799                 }
800                 if (displayId != Display.INVALID_DISPLAY
801                         && mA11yWindowManager.isTrackingWindowsLocked(displayId)) {
802                     shouldComputeWindows = true;
803                 }
804             }
805             if (shouldComputeWindows) {
806                 final WindowManagerInternal wm = LocalServices.getService(
807                         WindowManagerInternal.class);
808                 wm.computeWindowsForAccessibility(displayId);
809             }
810             synchronized (mLock) {
811                 notifyAccessibilityServicesDelayedLocked(event, false);
812                 notifyAccessibilityServicesDelayedLocked(event, true);
813                 mUiAutomationManager.sendAccessibilityEventLocked(event);
814             }
815         }
816 
817         if (OWN_PROCESS_ID != Binder.getCallingPid()) {
818             event.recycle();
819         }
820     }
821 
sendAccessibilityEventToInputFilter(AccessibilityEvent event)822     private void sendAccessibilityEventToInputFilter(AccessibilityEvent event) {
823         synchronized (mLock) {
824             if (mHasInputFilter && mInputFilter != null) {
825                 mInputFilter.notifyAccessibilityEvent(event);
826             }
827         }
828         event.recycle();
829     }
830 
831     /**
832      * This is the implementation of AccessibilityManager system API.
833      * System UI calls into this method through AccessibilityManager system API to register a
834      * system action.
835      */
836     @Override
registerSystemAction(RemoteAction action, int actionId)837     public void registerSystemAction(RemoteAction action, int actionId) {
838         if (mTraceManager.isA11yTracingEnabled()) {
839             mTraceManager.logTrace(LOG_TAG + ".registerSystemAction",
840                     "action=" + action + ";actionId=" + actionId);
841         }
842         mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
843         getSystemActionPerformer().registerSystemAction(actionId, action);
844     }
845 
846     /**
847      * This is the implementation of AccessibilityManager system API.
848      * System UI calls into this method through AccessibilityManager system API to unregister a
849      * system action.
850      */
851     @Override
unregisterSystemAction(int actionId)852     public void unregisterSystemAction(int actionId) {
853         if (mTraceManager.isA11yTracingEnabled()) {
854             mTraceManager.logTrace(LOG_TAG + ".unregisterSystemAction", "actionId=" + actionId);
855         }
856         mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
857         getSystemActionPerformer().unregisterSystemAction(actionId);
858     }
859 
getSystemActionPerformer()860     private SystemActionPerformer getSystemActionPerformer() {
861         if (mSystemActionPerformer == null) {
862             mSystemActionPerformer =
863                     new SystemActionPerformer(mContext, mWindowManagerService, null, this);
864         }
865         return mSystemActionPerformer;
866     }
867 
868     @Override
getInstalledAccessibilityServiceList(int userId)869     public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
870         if (mTraceManager.isA11yTracingEnabled()) {
871             mTraceManager.logTrace(LOG_TAG + ".getInstalledAccessibilityServiceList",
872                     "userId=" + userId);
873         }
874 
875         final int resolvedUserId;
876         final List<AccessibilityServiceInfo> serviceInfos;
877         synchronized (mLock) {
878             // We treat calls from a profile as if made by its parent as profiles
879             // share the accessibility state of the parent. The call below
880             // performs the current profile parent resolution.
881             resolvedUserId = mSecurityPolicy
882                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
883             serviceInfos = new ArrayList<>(
884                     getUserStateLocked(resolvedUserId).mInstalledServices);
885         }
886 
887         if (Binder.getCallingPid() == OWN_PROCESS_ID) {
888             return serviceInfos;
889         }
890         final PackageManagerInternal pm = LocalServices.getService(
891                 PackageManagerInternal.class);
892         final int callingUid = Binder.getCallingUid();
893         for (int i = serviceInfos.size() - 1; i >= 0; i--) {
894             final AccessibilityServiceInfo serviceInfo = serviceInfos.get(i);
895             if (pm.filterAppAccess(serviceInfo.getComponentName().getPackageName(), callingUid,
896                     resolvedUserId)) {
897                 serviceInfos.remove(i);
898             }
899         }
900         return serviceInfos;
901     }
902 
903     @Override
getEnabledAccessibilityServiceList(int feedbackType, int userId)904     public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType,
905             int userId) {
906         if (mTraceManager.isA11yTracingEnabled()) {
907             mTraceManager.logTrace(LOG_TAG + ".getEnabledAccessibilityServiceList",
908                     "feedbackType=" + feedbackType + ";userId=" + userId);
909         }
910 
911         synchronized (mLock) {
912             // We treat calls from a profile as if made by its parent as profiles
913             // share the accessibility state of the parent. The call below
914             // performs the current profile parent resolution.
915             final int resolvedUserId = mSecurityPolicy
916                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
917 
918             // The automation service can suppress other services.
919             final AccessibilityUserState userState = getUserStateLocked(resolvedUserId);
920             if (mUiAutomationManager.suppressingAccessibilityServicesLocked()) {
921                 return Collections.emptyList();
922             }
923 
924             final List<AccessibilityServiceConnection> services = userState.mBoundServices;
925             final int serviceCount = services.size();
926             final List<AccessibilityServiceInfo> result = new ArrayList<>(serviceCount);
927             for (int i = 0; i < serviceCount; ++i) {
928                 final AccessibilityServiceConnection service = services.get(i);
929                 if ((service.mFeedbackType & feedbackType) != 0) {
930                     result.add(service.getServiceInfo());
931                 }
932             }
933             return result;
934         }
935     }
936 
937     @Override
interrupt(int userId)938     public void interrupt(int userId) {
939         if (mTraceManager.isA11yTracingEnabled()) {
940             mTraceManager.logTrace(LOG_TAG + ".interrupt", "userId=" + userId);
941         }
942 
943         List<IAccessibilityServiceClient> interfacesToInterrupt;
944         synchronized (mLock) {
945             // We treat calls from a profile as if made by its parent as profiles
946             // share the accessibility state of the parent. The call below
947             // performs the current profile parent resolution.
948             final int resolvedUserId = mSecurityPolicy
949                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
950             // This method does nothing for a background user.
951             if (resolvedUserId != mCurrentUserId) {
952                 return;
953             }
954             List<AccessibilityServiceConnection> services =
955                     getUserStateLocked(resolvedUserId).mBoundServices;
956             int numServices = services.size();
957             interfacesToInterrupt = new ArrayList<>(numServices);
958             for (int i = 0; i < numServices; i++) {
959                 AccessibilityServiceConnection service = services.get(i);
960                 IBinder a11yServiceBinder = service.mService;
961                 IAccessibilityServiceClient a11yServiceInterface = service.mServiceInterface;
962                 if ((a11yServiceBinder != null) && (a11yServiceInterface != null)) {
963                     interfacesToInterrupt.add(a11yServiceInterface);
964                 }
965             }
966         }
967         for (int i = 0, count = interfacesToInterrupt.size(); i < count; i++) {
968             try {
969                 if (mTraceManager.isA11yTracingEnabled()) {
970                     mTraceManager.logTrace(LOG_TAG + ".IAccessibilityServiceClient.onInterrupt");
971                 }
972                 interfacesToInterrupt.get(i).onInterrupt();
973             } catch (RemoteException re) {
974                 Slog.e(LOG_TAG, "Error sending interrupt request to "
975                         + interfacesToInterrupt.get(i), re);
976             }
977         }
978     }
979 
980     @Override
addAccessibilityInteractionConnection(IWindow windowToken, IBinder leashToken, IAccessibilityInteractionConnection connection, String packageName, int userId)981     public int addAccessibilityInteractionConnection(IWindow windowToken, IBinder leashToken,
982             IAccessibilityInteractionConnection connection, String packageName,
983             int userId) throws RemoteException {
984         if (mTraceManager.isA11yTracingEnabled()) {
985             mTraceManager.logTrace(LOG_TAG + ".addAccessibilityInteractionConnection",
986                     "windowToken=" + windowToken + "leashToken=" + leashToken + ";connection="
987                             + connection + "; packageName=" + packageName + ";userId=" + userId);
988         }
989 
990         return mA11yWindowManager.addAccessibilityInteractionConnection(
991                 windowToken, leashToken, connection, packageName, userId);
992     }
993 
994     @Override
removeAccessibilityInteractionConnection(IWindow window)995     public void removeAccessibilityInteractionConnection(IWindow window) {
996         if (mTraceManager.isA11yTracingEnabled()) {
997             mTraceManager.logTrace(LOG_TAG + ".removeAccessibilityInteractionConnection",
998                     "window=" + window);
999         }
1000         mA11yWindowManager.removeAccessibilityInteractionConnection(window);
1001     }
1002 
1003     @Override
setPictureInPictureActionReplacingConnection( IAccessibilityInteractionConnection connection)1004     public void setPictureInPictureActionReplacingConnection(
1005             IAccessibilityInteractionConnection connection) throws RemoteException {
1006         if (mTraceManager.isA11yTracingEnabled()) {
1007             mTraceManager.logTrace(LOG_TAG + ".setPictureInPictureActionReplacingConnection",
1008                     "connection=" + connection);
1009         }
1010         mSecurityPolicy.enforceCallingPermission(Manifest.permission.MODIFY_ACCESSIBILITY_DATA,
1011                 SET_PIP_ACTION_REPLACEMENT);
1012         mA11yWindowManager.setPictureInPictureActionReplacingConnection(connection);
1013     }
1014 
1015     @Override
registerUiTestAutomationService(IBinder owner, IAccessibilityServiceClient serviceClient, AccessibilityServiceInfo accessibilityServiceInfo, int flags)1016     public void registerUiTestAutomationService(IBinder owner,
1017             IAccessibilityServiceClient serviceClient,
1018             AccessibilityServiceInfo accessibilityServiceInfo,
1019             int flags) {
1020         if (mTraceManager.isA11yTracingEnabled()) {
1021             mTraceManager.logTrace(LOG_TAG + ".registerUiTestAutomationService", "owner=" + owner
1022                     + ";serviceClient=" + serviceClient + ";accessibilityServiceInfo="
1023                     + accessibilityServiceInfo + ";flags=" + flags);
1024         }
1025 
1026         mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
1027                 FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE);
1028 
1029         synchronized (mLock) {
1030             mUiAutomationManager.registerUiTestAutomationServiceLocked(owner, serviceClient,
1031                     mContext, accessibilityServiceInfo, sIdCounter++, mMainHandler,
1032                     mSecurityPolicy, this, getTraceManager(), mWindowManagerService,
1033                     getSystemActionPerformer(), mA11yWindowManager, flags);
1034             onUserStateChangedLocked(getCurrentUserStateLocked());
1035         }
1036     }
1037 
1038     @Override
unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient)1039     public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) {
1040         if (mTraceManager.isA11yTracingEnabled()) {
1041             mTraceManager.logTrace(LOG_TAG + ".unregisterUiTestAutomationService",
1042                     "serviceClient=" + serviceClient);
1043         }
1044         synchronized (mLock) {
1045             mUiAutomationManager.unregisterUiTestAutomationServiceLocked(serviceClient);
1046         }
1047     }
1048 
1049     @Override
temporaryEnableAccessibilityStateUntilKeyguardRemoved( ComponentName service, boolean touchExplorationEnabled)1050     public void temporaryEnableAccessibilityStateUntilKeyguardRemoved(
1051             ComponentName service, boolean touchExplorationEnabled) {
1052         if (mTraceManager.isA11yTracingEnabled()) {
1053             mTraceManager.logTrace(
1054                     LOG_TAG + ".temporaryEnableAccessibilityStateUntilKeyguardRemoved",
1055                     "service=" + service + ";touchExplorationEnabled=" + touchExplorationEnabled);
1056         }
1057 
1058         mSecurityPolicy.enforceCallingPermission(
1059                 Manifest.permission.TEMPORARY_ENABLE_ACCESSIBILITY,
1060                 TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED);
1061         if (!mWindowManagerService.isKeyguardLocked()) {
1062             return;
1063         }
1064         synchronized (mLock) {
1065             // Set the temporary state.
1066             AccessibilityUserState userState = getCurrentUserStateLocked();
1067 
1068             userState.setTouchExplorationEnabledLocked(touchExplorationEnabled);
1069             userState.setDisplayMagnificationEnabledLocked(false);
1070             userState.disableShortcutMagnificationLocked();
1071             userState.setAutoclickEnabledLocked(false);
1072             userState.mEnabledServices.clear();
1073             userState.mEnabledServices.add(service);
1074             userState.getBindingServicesLocked().clear();
1075             userState.getCrashedServicesLocked().clear();
1076             userState.mTouchExplorationGrantedServices.clear();
1077             userState.mTouchExplorationGrantedServices.add(service);
1078 
1079             // User the current state instead settings.
1080             onUserStateChangedLocked(userState);
1081         }
1082     }
1083 
1084     @Override
getWindowToken(int windowId, int userId)1085     public IBinder getWindowToken(int windowId, int userId) {
1086         if (mTraceManager.isA11yTracingEnabled()) {
1087             mTraceManager.logTrace(LOG_TAG + ".getWindowToken",
1088                     "windowId=" + windowId + ";userId=" + userId);
1089         }
1090 
1091         mSecurityPolicy.enforceCallingPermission(
1092                 Manifest.permission.RETRIEVE_WINDOW_TOKEN,
1093                 GET_WINDOW_TOKEN);
1094         synchronized (mLock) {
1095             // We treat calls from a profile as if made by its parent as profiles
1096             // share the accessibility state of the parent. The call below
1097             // performs the current profile parent resolution.
1098             final int resolvedUserId = mSecurityPolicy
1099                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
1100             if (resolvedUserId != mCurrentUserId) {
1101                 return null;
1102             }
1103             final AccessibilityWindowInfo accessibilityWindowInfo = mA11yWindowManager
1104                     .findA11yWindowInfoByIdLocked(windowId);
1105             if (accessibilityWindowInfo == null) {
1106                 return null;
1107             }
1108             // We use AccessibilityWindowInfo#getId instead of windowId. When the windowId comes
1109             // from an embedded hierarchy, the system can't find correct window token because
1110             // embedded hierarchy doesn't have windowInfo. Calling
1111             // AccessibilityWindowManager#findA11yWindowInfoByIdLocked can look for its parent's
1112             // windowInfo, so it is safer to use AccessibilityWindowInfo#getId
1113             // to get window token to find real window.
1114             return mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(userId,
1115                     accessibilityWindowInfo.getId());
1116         }
1117     }
1118 
1119     /**
1120      * Invoked remotely over AIDL by SysUi when the accessibility button within the system's
1121      * navigation area has been clicked.
1122      *
1123      * @param displayId The logical display id.
1124      * @param targetName The flattened {@link ComponentName} string or the class name of a system
1125      *        class implementing a supported accessibility feature, or {@code null} if there's no
1126      *        specified target.
1127      */
1128     @Override
notifyAccessibilityButtonClicked(int displayId, String targetName)1129     public void notifyAccessibilityButtonClicked(int displayId, String targetName) {
1130         if (mTraceManager.isA11yTracingEnabled()) {
1131             mTraceManager.logTrace(LOG_TAG + ".notifyAccessibilityButtonClicked",
1132                     "displayId=" + displayId + ";targetName=" + targetName);
1133         }
1134 
1135         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE)
1136                 != PackageManager.PERMISSION_GRANTED) {
1137             throw new SecurityException("Caller does not hold permission "
1138                     + android.Manifest.permission.STATUS_BAR_SERVICE);
1139         }
1140         if (targetName == null) {
1141             synchronized (mLock) {
1142                 final AccessibilityUserState userState = getCurrentUserStateLocked();
1143                 targetName = userState.getTargetAssignedToAccessibilityButton();
1144             }
1145         }
1146         mMainHandler.sendMessage(obtainMessage(
1147                 AccessibilityManagerService::performAccessibilityShortcutInternal, this,
1148                 displayId, ACCESSIBILITY_BUTTON, targetName));
1149     }
1150 
1151     /**
1152      * Invoked remotely over AIDL by SysUi when the visibility of the accessibility
1153      * button within the system's navigation area has changed.
1154      *
1155      * @param shown {@code true} if the accessibility button is shown to the
1156      *                  user, {@code false} otherwise
1157      */
1158     @Override
notifyAccessibilityButtonVisibilityChanged(boolean shown)1159     public void notifyAccessibilityButtonVisibilityChanged(boolean shown) {
1160         if (mTraceManager.isA11yTracingEnabled()) {
1161             mTraceManager.logTrace(LOG_TAG + ".notifyAccessibilityButtonVisibilityChanged",
1162                     "shown=" + shown);
1163         }
1164 
1165         mSecurityPolicy.enforceCallingOrSelfPermission(
1166                 android.Manifest.permission.STATUS_BAR_SERVICE);
1167         synchronized (mLock) {
1168             notifyAccessibilityButtonVisibilityChangedLocked(shown);
1169         }
1170     }
1171 
1172     /**
1173      * Called when a gesture is detected on a display.
1174      *
1175      * @param gestureEvent the detail of the gesture.
1176      * @return true if the event is handled.
1177      */
onGesture(AccessibilityGestureEvent gestureEvent)1178     public boolean onGesture(AccessibilityGestureEvent gestureEvent) {
1179         synchronized (mLock) {
1180             boolean handled = notifyGestureLocked(gestureEvent, false);
1181             if (!handled) {
1182                 handled = notifyGestureLocked(gestureEvent, true);
1183             }
1184             return handled;
1185         }
1186     }
1187 
1188     /**
1189      * Called when the system action list is changed.
1190      */
1191     @Override
onSystemActionsChanged()1192     public void onSystemActionsChanged() {
1193         if (mTraceManager.isA11yTracingEnabled()) {
1194             mTraceManager.logTrace(LOG_TAG + ".onSystemActionsChanged");
1195         }
1196 
1197         synchronized (mLock) {
1198             AccessibilityUserState state = getCurrentUserStateLocked();
1199             notifySystemActionsChangedLocked(state);
1200         }
1201     }
1202 
1203     @VisibleForTesting
notifySystemActionsChangedLocked(AccessibilityUserState userState)1204     void notifySystemActionsChangedLocked(AccessibilityUserState userState) {
1205         for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
1206             AccessibilityServiceConnection service = userState.mBoundServices.get(i);
1207             service.notifySystemActionsChangedLocked();
1208         }
1209     }
1210 
1211     @VisibleForTesting
notifyKeyEvent(KeyEvent event, int policyFlags)1212     public boolean notifyKeyEvent(KeyEvent event, int policyFlags) {
1213         synchronized (mLock) {
1214             List<AccessibilityServiceConnection> boundServices =
1215                     getCurrentUserStateLocked().mBoundServices;
1216             if (boundServices.isEmpty()) {
1217                 return false;
1218             }
1219             return getKeyEventDispatcher().notifyKeyEventLocked(event, policyFlags, boundServices);
1220         }
1221     }
1222 
1223     /**
1224      * Called by the MagnificationController when the state of display
1225      * magnification changes.
1226      *
1227      * @param displayId The logical display id.
1228      * @param region the new magnified region, may be empty if
1229      *               magnification is not enabled (e.g. scale is 1)
1230      * @param scale the new scale
1231      * @param centerX the new screen-relative center X coordinate
1232      * @param centerY the new screen-relative center Y coordinate
1233      */
notifyMagnificationChanged(int displayId, @NonNull Region region, float scale, float centerX, float centerY)1234     public void notifyMagnificationChanged(int displayId, @NonNull Region region,
1235             float scale, float centerX, float centerY) {
1236         synchronized (mLock) {
1237             notifyClearAccessibilityCacheLocked();
1238             notifyMagnificationChangedLocked(displayId, region, scale, centerX, centerY);
1239         }
1240     }
1241 
1242     /**
1243      * Called by AccessibilityInputFilter when it creates or destroys the motionEventInjector.
1244      * Not using a getter because the AccessibilityInputFilter isn't thread-safe
1245      *
1246      * @param motionEventInjectors The array of motionEventInjectors. May be null.
1247      *
1248      */
setMotionEventInjectors(SparseArray<MotionEventInjector> motionEventInjectors)1249     void setMotionEventInjectors(SparseArray<MotionEventInjector> motionEventInjectors) {
1250         synchronized (mLock) {
1251             mMotionEventInjectors = motionEventInjectors;
1252             // We may be waiting on this object being set
1253             mLock.notifyAll();
1254         }
1255     }
1256 
1257     @Override
getMotionEventInjectorForDisplayLocked(int displayId)1258     public @Nullable MotionEventInjector getMotionEventInjectorForDisplayLocked(int displayId) {
1259         if (mTraceManager.isA11yTracingEnabled()) {
1260             mTraceManager.logTrace(LOG_TAG + ".getMotionEventInjectorForDisplayLocked",
1261                     "displayId=" + displayId);
1262         }
1263 
1264         final long endMillis = SystemClock.uptimeMillis() + WAIT_MOTION_INJECTOR_TIMEOUT_MILLIS;
1265         MotionEventInjector motionEventInjector = null;
1266         while ((mMotionEventInjectors == null) && (SystemClock.uptimeMillis() < endMillis)) {
1267             try {
1268                 mLock.wait(endMillis - SystemClock.uptimeMillis());
1269             } catch (InterruptedException ie) {
1270                 /* ignore */
1271             }
1272         }
1273         if (mMotionEventInjectors == null) {
1274             Slog.e(LOG_TAG, "MotionEventInjector installation timed out");
1275         } else {
1276             motionEventInjector = mMotionEventInjectors.get(displayId);
1277         }
1278         return motionEventInjector;
1279     }
1280 
1281     /**
1282      * Gets a point within the accessibility focused node where we can send down
1283      * and up events to perform a click.
1284      *
1285      * @param outPoint The click point to populate.
1286      * @return Whether accessibility a click point was found and set.
1287      */
1288     // TODO: (multi-display) Make sure this works for multiple displays.
getAccessibilityFocusClickPointInScreen(Point outPoint)1289     public boolean getAccessibilityFocusClickPointInScreen(Point outPoint) {
1290         return getInteractionBridge().getAccessibilityFocusClickPointInScreenNotLocked(outPoint);
1291     }
1292 
1293     /**
1294      * Perform an accessibility action on the view that currently has accessibility focus.
1295      * Has no effect if no item has accessibility focus, if the item with accessibility
1296      * focus does not expose the specified action, or if the action fails.
1297      *
1298      * @param action The action to perform.
1299      *
1300      * @return {@code true} if the action was performed. {@code false} if it was not.
1301      */
performActionOnAccessibilityFocusedItem( AccessibilityNodeInfo.AccessibilityAction action)1302     public boolean performActionOnAccessibilityFocusedItem(
1303             AccessibilityNodeInfo.AccessibilityAction action) {
1304         return getInteractionBridge().performActionOnAccessibilityFocusedItemNotLocked(action);
1305     }
1306 
1307     /**
1308      * Returns true if accessibility focus is confined to the active window.
1309      */
accessibilityFocusOnlyInActiveWindow()1310     public boolean accessibilityFocusOnlyInActiveWindow() {
1311         synchronized (mLock) {
1312             return mA11yWindowManager.isTrackingWindowsLocked();
1313         }
1314     }
1315 
1316     /**
1317      * Gets the bounds of a window.
1318      *
1319      * @param outBounds The output to which to write the bounds.
1320      */
getWindowBounds(int windowId, Rect outBounds)1321     boolean getWindowBounds(int windowId, Rect outBounds) {
1322         IBinder token;
1323         synchronized (mLock) {
1324             token = getWindowToken(windowId, mCurrentUserId);
1325         }
1326         mWindowManagerService.getWindowFrame(token, outBounds);
1327         if (!outBounds.isEmpty()) {
1328             return true;
1329         }
1330         return false;
1331     }
1332 
getActiveWindowId()1333     public int getActiveWindowId() {
1334         return mA11yWindowManager.getActiveWindowId(mCurrentUserId);
1335     }
1336 
onTouchInteractionStart()1337     public void onTouchInteractionStart() {
1338         mA11yWindowManager.onTouchInteractionStart();
1339     }
1340 
onTouchInteractionEnd()1341     public void onTouchInteractionEnd() {
1342         mA11yWindowManager.onTouchInteractionEnd();
1343     }
1344 
switchUser(int userId)1345     private void switchUser(int userId) {
1346         synchronized (mLock) {
1347             if (mCurrentUserId == userId && mInitialized) {
1348                 return;
1349             }
1350 
1351             // Disconnect from services for the old user.
1352             AccessibilityUserState oldUserState = getCurrentUserStateLocked();
1353             oldUserState.onSwitchToAnotherUserLocked();
1354 
1355             // Disable the local managers for the old user.
1356             if (oldUserState.mUserClients.getRegisteredCallbackCount() > 0) {
1357                 mMainHandler.sendMessage(obtainMessage(
1358                         AccessibilityManagerService::sendStateToClients,
1359                         this, 0, oldUserState.mUserId));
1360             }
1361 
1362             // Announce user changes only if more that one exist.
1363             UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1364             final boolean announceNewUser = userManager.getUsers().size() > 1;
1365 
1366             // The user changed.
1367             mCurrentUserId = userId;
1368 
1369             mMagnificationController.updateUserIdIfNeeded(mCurrentUserId);
1370             AccessibilityUserState userState = getCurrentUserStateLocked();
1371 
1372             readConfigurationForUserStateLocked(userState);
1373             mSecurityPolicy.onSwitchUserLocked(mCurrentUserId, userState.mEnabledServices);
1374             // Even if reading did not yield change, we have to update
1375             // the state since the context in which the current user
1376             // state was used has changed since it was inactive.
1377             onUserStateChangedLocked(userState);
1378             // It's better to have this migration in SettingsProvider. Unfortunately,
1379             // SettingsProvider migrated database in a very early stage which A11yManagerService
1380             // haven't finished or started the initialization. We cannot get enough information from
1381             // A11yManagerService to execute these migrations in SettingsProvider. Passing 0 for
1382             // restoreFromSdkInt to have this migration check execute every time, because we did not
1383             // find out a way to detect the device finished the OTA and switch the user.
1384             migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null,
1385                     /* restoreFromSdkInt = */0);
1386 
1387             if (announceNewUser) {
1388                 // Schedule announcement of the current user if needed.
1389                 mMainHandler.sendMessageDelayed(
1390                         obtainMessage(AccessibilityManagerService::announceNewUserIfNeeded, this),
1391                         WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS);
1392             }
1393         }
1394     }
1395 
announceNewUserIfNeeded()1396     private void announceNewUserIfNeeded() {
1397         synchronized (mLock) {
1398             AccessibilityUserState userState = getCurrentUserStateLocked();
1399             if (userState.isHandlingAccessibilityEventsLocked()) {
1400                 UserManager userManager = (UserManager) mContext.getSystemService(
1401                         Context.USER_SERVICE);
1402                 String message = mContext.getString(R.string.user_switched,
1403                         userManager.getUserInfo(mCurrentUserId).name);
1404                 AccessibilityEvent event = AccessibilityEvent.obtain(
1405                         AccessibilityEvent.TYPE_ANNOUNCEMENT);
1406                 event.getText().add(message);
1407                 sendAccessibilityEventLocked(event, mCurrentUserId);
1408             }
1409         }
1410     }
1411 
unlockUser(int userId)1412     private void unlockUser(int userId) {
1413         synchronized (mLock) {
1414             int parentUserId = mSecurityPolicy.resolveProfileParentLocked(userId);
1415             if (parentUserId == mCurrentUserId) {
1416                 AccessibilityUserState userState = getUserStateLocked(mCurrentUserId);
1417                 onUserStateChangedLocked(userState);
1418             }
1419         }
1420     }
1421 
removeUser(int userId)1422     private void removeUser(int userId) {
1423         synchronized (mLock) {
1424             mUserStates.remove(userId);
1425         }
1426     }
1427 
1428     // Called only during settings restore; currently supports only the owner user
1429     // TODO: http://b/22388012
restoreEnabledAccessibilityServicesLocked(String oldSetting, String newSetting, int restoreFromSdkInt)1430     void restoreEnabledAccessibilityServicesLocked(String oldSetting, String newSetting,
1431             int restoreFromSdkInt) {
1432         readComponentNamesFromStringLocked(oldSetting, mTempComponentNameSet, false);
1433         readComponentNamesFromStringLocked(newSetting, mTempComponentNameSet, true);
1434 
1435         AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM);
1436         userState.mEnabledServices.clear();
1437         userState.mEnabledServices.addAll(mTempComponentNameSet);
1438         persistComponentNamesToSettingLocked(
1439                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
1440                 userState.mEnabledServices,
1441                 UserHandle.USER_SYSTEM);
1442         onUserStateChangedLocked(userState);
1443         migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null, restoreFromSdkInt);
1444     }
1445 
1446     /**
1447      * User could enable accessibility services and configure accessibility button during the SUW.
1448      * Merges current value of accessibility button settings into the restored one to make sure
1449      * user's preferences of accessibility button updated in SUW are not lost.
1450      *
1451      * Called only during settings restore; currently supports only the owner user
1452      * TODO: http://b/22388012
1453      */
restoreAccessibilityButtonTargetsLocked(String oldSetting, String newSetting)1454     void restoreAccessibilityButtonTargetsLocked(String oldSetting, String newSetting) {
1455         final Set<String> targetsFromSetting = new ArraySet<>();
1456         readColonDelimitedStringToSet(oldSetting, str -> str, targetsFromSetting,
1457                 /* doMerge = */false);
1458         readColonDelimitedStringToSet(newSetting, str -> str, targetsFromSetting,
1459                 /* doMerge = */true);
1460 
1461         final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM);
1462         userState.mAccessibilityButtonTargets.clear();
1463         userState.mAccessibilityButtonTargets.addAll(targetsFromSetting);
1464         persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
1465                 UserHandle.USER_SYSTEM, userState.mAccessibilityButtonTargets, str -> str);
1466 
1467         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
1468         onUserStateChangedLocked(userState);
1469     }
1470 
getClientStateLocked(AccessibilityUserState userState)1471     private int getClientStateLocked(AccessibilityUserState userState) {
1472         return userState.getClientStateLocked(
1473             mUiAutomationManager.isUiAutomationRunningLocked(),
1474             mTraceManager.isA11yTracingEnabled());
1475     }
1476 
getInteractionBridge()1477     private InteractionBridge getInteractionBridge() {
1478         synchronized (mLock) {
1479             if (mInteractionBridge == null) {
1480                 mInteractionBridge = new InteractionBridge();
1481             }
1482             return mInteractionBridge;
1483         }
1484     }
1485 
notifyGestureLocked(AccessibilityGestureEvent gestureEvent, boolean isDefault)1486     private boolean notifyGestureLocked(AccessibilityGestureEvent gestureEvent, boolean isDefault) {
1487         // TODO: Now we are giving the gestures to the last enabled
1488         //       service that can handle them which is the last one
1489         //       in our list since we write the last enabled as the
1490         //       last record in the enabled services setting. Ideally,
1491         //       the user should make the call which service handles
1492         //       gestures. However, only one service should handle
1493         //       gestures to avoid user frustration when different
1494         //       behavior is observed from different combinations of
1495         //       enabled accessibility services.
1496         AccessibilityUserState state = getCurrentUserStateLocked();
1497         for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
1498             AccessibilityServiceConnection service = state.mBoundServices.get(i);
1499             if (service.mRequestTouchExplorationMode && service.mIsDefault == isDefault) {
1500                 service.notifyGesture(gestureEvent);
1501                 return true;
1502             }
1503         }
1504         return false;
1505     }
1506 
notifyClearAccessibilityCacheLocked()1507     private void notifyClearAccessibilityCacheLocked() {
1508         AccessibilityUserState state = getCurrentUserStateLocked();
1509         for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
1510             AccessibilityServiceConnection service = state.mBoundServices.get(i);
1511             service.notifyClearAccessibilityNodeInfoCache();
1512         }
1513     }
1514 
notifyMagnificationChangedLocked(int displayId, @NonNull Region region, float scale, float centerX, float centerY)1515     private void notifyMagnificationChangedLocked(int displayId, @NonNull Region region,
1516             float scale, float centerX, float centerY) {
1517         final AccessibilityUserState state = getCurrentUserStateLocked();
1518         for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
1519             final AccessibilityServiceConnection service = state.mBoundServices.get(i);
1520             service.notifyMagnificationChangedLocked(displayId, region, scale, centerX, centerY);
1521         }
1522     }
1523 
sendAccessibilityButtonToInputFilter(int displayId)1524     private void sendAccessibilityButtonToInputFilter(int displayId) {
1525         synchronized (mLock) {
1526             if (mHasInputFilter && mInputFilter != null) {
1527                 mInputFilter.notifyAccessibilityButtonClicked(displayId);
1528             }
1529         }
1530     }
1531 
showAccessibilityTargetsSelection(int displayId, @ShortcutType int shortcutType)1532     private void showAccessibilityTargetsSelection(int displayId,
1533             @ShortcutType int shortcutType) {
1534         final Intent intent = new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
1535         final String chooserClassName = (shortcutType == ACCESSIBILITY_SHORTCUT_KEY)
1536                 ? AccessibilityShortcutChooserActivity.class.getName()
1537                 : AccessibilityButtonChooserActivity.class.getName();
1538         intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName);
1539         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
1540         final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
1541         mContext.startActivityAsUser(intent, bundle, UserHandle.of(mCurrentUserId));
1542     }
1543 
launchShortcutTargetActivity(int displayId, ComponentName name)1544     private void launchShortcutTargetActivity(int displayId, ComponentName name) {
1545         final Intent intent = new Intent();
1546         final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
1547         intent.setComponent(name);
1548         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1549         try {
1550             mContext.startActivityAsUser(intent, bundle, UserHandle.of(mCurrentUserId));
1551         } catch (ActivityNotFoundException ignore) {
1552             // ignore the exception
1553         }
1554     }
1555 
notifyAccessibilityButtonVisibilityChangedLocked(boolean available)1556     private void notifyAccessibilityButtonVisibilityChangedLocked(boolean available) {
1557         final AccessibilityUserState state = getCurrentUserStateLocked();
1558         mIsAccessibilityButtonShown = available;
1559         for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
1560             final AccessibilityServiceConnection clientConnection = state.mBoundServices.get(i);
1561             if (clientConnection.mRequestAccessibilityButton) {
1562                 clientConnection.notifyAccessibilityButtonAvailabilityChangedLocked(
1563                         clientConnection.isAccessibilityButtonAvailableLocked(state));
1564             }
1565         }
1566     }
1567 
readInstalledAccessibilityServiceLocked(AccessibilityUserState userState)1568     private boolean readInstalledAccessibilityServiceLocked(AccessibilityUserState userState) {
1569         mTempAccessibilityServiceInfoList.clear();
1570 
1571         int flags = PackageManager.GET_SERVICES
1572                 | PackageManager.GET_META_DATA
1573                 | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
1574                 | PackageManager.MATCH_DIRECT_BOOT_AWARE
1575                 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
1576 
1577         if (userState.getBindInstantServiceAllowedLocked()) {
1578             flags |= PackageManager.MATCH_INSTANT;
1579         }
1580 
1581         List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser(
1582                 new Intent(AccessibilityService.SERVICE_INTERFACE), flags, mCurrentUserId);
1583 
1584         for (int i = 0, count = installedServices.size(); i < count; i++) {
1585             ResolveInfo resolveInfo = installedServices.get(i);
1586             ServiceInfo serviceInfo = resolveInfo.serviceInfo;
1587 
1588             if (!mSecurityPolicy.canRegisterService(serviceInfo)) {
1589                 continue;
1590             }
1591 
1592             AccessibilityServiceInfo accessibilityServiceInfo;
1593             try {
1594                 accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext);
1595                 if (userState.mCrashedServices.contains(serviceInfo.getComponentName())) {
1596                     // Restore the crashed attribute.
1597                     accessibilityServiceInfo.crashed = true;
1598                 }
1599                 mTempAccessibilityServiceInfoList.add(accessibilityServiceInfo);
1600             } catch (XmlPullParserException | IOException xppe) {
1601                 Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe);
1602             }
1603         }
1604 
1605         if (!mTempAccessibilityServiceInfoList.equals(userState.mInstalledServices)) {
1606             userState.mInstalledServices.clear();
1607             userState.mInstalledServices.addAll(mTempAccessibilityServiceInfoList);
1608             mTempAccessibilityServiceInfoList.clear();
1609             return true;
1610         }
1611 
1612         mTempAccessibilityServiceInfoList.clear();
1613         return false;
1614     }
1615 
readInstalledAccessibilityShortcutLocked(AccessibilityUserState userState)1616     private boolean readInstalledAccessibilityShortcutLocked(AccessibilityUserState userState) {
1617         final List<AccessibilityShortcutInfo> shortcutInfos = AccessibilityManager
1618                 .getInstance(mContext).getInstalledAccessibilityShortcutListAsUser(
1619                         mContext, mCurrentUserId);
1620         if (!shortcutInfos.equals(userState.mInstalledShortcuts)) {
1621             userState.mInstalledShortcuts.clear();
1622             userState.mInstalledShortcuts.addAll(shortcutInfos);
1623             return true;
1624         }
1625         return false;
1626     }
1627 
readEnabledAccessibilityServicesLocked(AccessibilityUserState userState)1628     private boolean readEnabledAccessibilityServicesLocked(AccessibilityUserState userState) {
1629         mTempComponentNameSet.clear();
1630         readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
1631                 userState.mUserId, mTempComponentNameSet);
1632         if (!mTempComponentNameSet.equals(userState.mEnabledServices)) {
1633             userState.mEnabledServices.clear();
1634             userState.mEnabledServices.addAll(mTempComponentNameSet);
1635             mTempComponentNameSet.clear();
1636             return true;
1637         }
1638         mTempComponentNameSet.clear();
1639         return false;
1640     }
1641 
readTouchExplorationGrantedAccessibilityServicesLocked( AccessibilityUserState userState)1642     private boolean readTouchExplorationGrantedAccessibilityServicesLocked(
1643             AccessibilityUserState userState) {
1644         mTempComponentNameSet.clear();
1645         readComponentNamesFromSettingLocked(
1646                 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
1647                 userState.mUserId, mTempComponentNameSet);
1648         if (!mTempComponentNameSet.equals(userState.mTouchExplorationGrantedServices)) {
1649             userState.mTouchExplorationGrantedServices.clear();
1650             userState.mTouchExplorationGrantedServices.addAll(mTempComponentNameSet);
1651             mTempComponentNameSet.clear();
1652             return true;
1653         }
1654         mTempComponentNameSet.clear();
1655         return false;
1656     }
1657 
1658     /**
1659      * Performs {@link AccessibilityService}s delayed notification. The delay is configurable
1660      * and denotes the period after the last event before notifying the service.
1661      *
1662      * @param event The event.
1663      * @param isDefault True to notify default listeners, not default services.
1664      */
notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event, boolean isDefault)1665     private void notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event,
1666             boolean isDefault) {
1667         try {
1668             AccessibilityUserState state = getCurrentUserStateLocked();
1669             for (int i = 0, count = state.mBoundServices.size(); i < count; i++) {
1670                 AccessibilityServiceConnection service = state.mBoundServices.get(i);
1671 
1672                 if (service.mIsDefault == isDefault) {
1673                     service.notifyAccessibilityEvent(event);
1674                 }
1675             }
1676         } catch (IndexOutOfBoundsException oobe) {
1677             // An out of bounds exception can happen if services are going away
1678             // as the for loop is running. If that happens, just bail because
1679             // there are no more services to notify.
1680         }
1681     }
1682 
updateRelevantEventsLocked(AccessibilityUserState userState)1683     private void updateRelevantEventsLocked(AccessibilityUserState userState) {
1684         mMainHandler.post(() -> {
1685             broadcastToClients(userState, ignoreRemoteException(client -> {
1686                 int relevantEventTypes;
1687                 boolean changed = false;
1688                 synchronized (mLock) {
1689                     relevantEventTypes = computeRelevantEventTypesLocked(userState, client);
1690 
1691                     if (client.mLastSentRelevantEventTypes != relevantEventTypes) {
1692                         client.mLastSentRelevantEventTypes = relevantEventTypes;
1693                         changed = true;
1694                     }
1695                 }
1696                 if (changed) {
1697                     client.mCallback.setRelevantEventTypes(relevantEventTypes);
1698                 }
1699             }));
1700         });
1701     }
1702 
computeRelevantEventTypesLocked(AccessibilityUserState userState, Client client)1703     private int computeRelevantEventTypesLocked(AccessibilityUserState userState, Client client) {
1704         int relevantEventTypes = 0;
1705 
1706         int serviceCount = userState.mBoundServices.size();
1707         for (int i = 0; i < serviceCount; i++) {
1708             AccessibilityServiceConnection service = userState.mBoundServices.get(i);
1709             relevantEventTypes |= isClientInPackageAllowlist(service.getServiceInfo(), client)
1710                     ? service.getRelevantEventTypes()
1711                     : 0;
1712         }
1713 
1714         relevantEventTypes |= isClientInPackageAllowlist(
1715                 mUiAutomationManager.getServiceInfo(), client)
1716                 ? mUiAutomationManager.getRelevantEventTypes()
1717                 : 0;
1718         return relevantEventTypes;
1719     }
1720 
updateMagnificationModeChangeSettingsLocked(AccessibilityUserState userState)1721     private void updateMagnificationModeChangeSettingsLocked(AccessibilityUserState userState) {
1722         if (userState.mUserId != mCurrentUserId) {
1723             return;
1724         }
1725         // New mode is invalid, so ignore and restore it.
1726         if (fallBackMagnificationModeSettingsLocked(userState)) {
1727             return;
1728         }
1729         mMagnificationController.transitionMagnificationModeLocked(
1730                 Display.DEFAULT_DISPLAY, userState.getMagnificationModeLocked(),
1731                 this::onMagnificationTransitionEndedLocked);
1732     }
1733 
1734     /**
1735      * Called when the magnification mode transition is completed.
1736      */
onMagnificationTransitionEndedLocked(boolean success)1737     void onMagnificationTransitionEndedLocked(boolean success) {
1738         final AccessibilityUserState userState = getCurrentUserStateLocked();
1739         final int previousMode = userState.getMagnificationModeLocked()
1740                 ^ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
1741         if (!success && previousMode != 0) {
1742             userState.setMagnificationModeLocked(previousMode);
1743             persistMagnificationModeSettingLocked(previousMode);
1744         } else {
1745             mMainHandler.sendMessage(obtainMessage(
1746                     AccessibilityManagerService::notifyRefreshMagnificationModeToInputFilter,
1747                     this));
1748         }
1749     }
1750 
notifyRefreshMagnificationModeToInputFilter()1751     private void notifyRefreshMagnificationModeToInputFilter() {
1752         synchronized (mLock) {
1753             if (!mHasInputFilter) {
1754                 return;
1755             }
1756             // TODO: notify the mode change on specified display.
1757             final ArrayList<Display> displays = getValidDisplayList();
1758             for (int i = 0; i < displays.size(); i++) {
1759                 final Display display = displays.get(i);
1760                 if (display != null) {
1761                     mInputFilter.refreshMagnificationMode(display);
1762                 }
1763             }
1764         }
1765     }
1766 
isClientInPackageAllowlist( @ullable AccessibilityServiceInfo serviceInfo, Client client)1767     private static boolean isClientInPackageAllowlist(
1768             @Nullable AccessibilityServiceInfo serviceInfo, Client client) {
1769         if (serviceInfo == null) return false;
1770 
1771         String[] clientPackages = client.mPackageNames;
1772         boolean result = ArrayUtils.isEmpty(serviceInfo.packageNames);
1773         if (!result && clientPackages != null) {
1774             for (String packageName : clientPackages) {
1775                 if (ArrayUtils.contains(serviceInfo.packageNames, packageName)) {
1776                     result = true;
1777                     break;
1778                 }
1779             }
1780         }
1781         if (!result) {
1782             if (DEBUG) {
1783                 Slog.d(LOG_TAG, "Dropping events: "
1784                         + Arrays.toString(clientPackages) + " -> "
1785                         + serviceInfo.getComponentName().flattenToShortString()
1786                         + " due to not being in package allowlist "
1787                         + Arrays.toString(serviceInfo.packageNames));
1788             }
1789         }
1790 
1791         return result;
1792     }
1793 
broadcastToClients( AccessibilityUserState userState, Consumer<Client> clientAction)1794     private void broadcastToClients(
1795             AccessibilityUserState userState, Consumer<Client> clientAction) {
1796         mGlobalClients.broadcastForEachCookie(clientAction);
1797         userState.mUserClients.broadcastForEachCookie(clientAction);
1798     }
1799 
1800     /**
1801      * Populates a set with the {@link ComponentName}s stored in a colon
1802      * separated value setting for a given user.
1803      *
1804      * @param settingName The setting to parse.
1805      * @param userId The user id.
1806      * @param outComponentNames The output component names.
1807      */
readComponentNamesFromSettingLocked(String settingName, int userId, Set<ComponentName> outComponentNames)1808     private void readComponentNamesFromSettingLocked(String settingName, int userId,
1809             Set<ComponentName> outComponentNames) {
1810         readColonDelimitedSettingToSet(settingName, userId,
1811                 str -> ComponentName.unflattenFromString(str), outComponentNames);
1812     }
1813 
1814     /**
1815      * Populates a set with the {@link ComponentName}s contained in a colon-delimited string.
1816      *
1817      * @param names The colon-delimited string to parse.
1818      * @param outComponentNames The set of component names to be populated based on
1819      *    the contents of the <code>names</code> string.
1820      * @param doMerge If true, the parsed component names will be merged into the output
1821      *    set, rather than replacing the set's existing contents entirely.
1822      */
readComponentNamesFromStringLocked(String names, Set<ComponentName> outComponentNames, boolean doMerge)1823     private void readComponentNamesFromStringLocked(String names,
1824             Set<ComponentName> outComponentNames,
1825             boolean doMerge) {
1826         readColonDelimitedStringToSet(names, str -> ComponentName.unflattenFromString(str),
1827                 outComponentNames, doMerge);
1828     }
1829 
1830     @Override
persistComponentNamesToSettingLocked(String settingName, Set<ComponentName> componentNames, int userId)1831     public void persistComponentNamesToSettingLocked(String settingName,
1832             Set<ComponentName> componentNames, int userId) {
1833         if (mTraceManager.isA11yTracingEnabled()) {
1834             mTraceManager.logTrace(LOG_TAG + ".persistComponentNamesToSettingLocked",
1835                     "settingName=" + settingName + ";componentNames=" + componentNames + ";userId="
1836                             + userId);
1837         }
1838 
1839         persistColonDelimitedSetToSettingLocked(settingName, userId, componentNames,
1840                 componentName -> componentName.flattenToShortString());
1841     }
1842 
readColonDelimitedSettingToSet(String settingName, int userId, Function<String, T> toItem, Set<T> outSet)1843     private <T> void readColonDelimitedSettingToSet(String settingName, int userId,
1844             Function<String, T> toItem, Set<T> outSet) {
1845         final String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
1846                 settingName, userId);
1847         readColonDelimitedStringToSet(settingValue, toItem, outSet, false);
1848     }
1849 
readColonDelimitedStringToSet(String names, Function<String, T> toItem, Set<T> outSet, boolean doMerge)1850     private <T> void readColonDelimitedStringToSet(String names, Function<String, T> toItem,
1851             Set<T> outSet, boolean doMerge) {
1852         if (!doMerge) {
1853             outSet.clear();
1854         }
1855         if (!TextUtils.isEmpty(names)) {
1856             final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
1857             splitter.setString(names);
1858             while (splitter.hasNext()) {
1859                 final String str = splitter.next();
1860                 if (TextUtils.isEmpty(str)) {
1861                     continue;
1862                 }
1863                 final T item = toItem.apply(str);
1864                 if (item != null) {
1865                     outSet.add(item);
1866                 }
1867             }
1868         }
1869     }
1870 
persistColonDelimitedSetToSettingLocked(String settingName, int userId, Set<T> set, Function<T, String> toString)1871     private <T> void persistColonDelimitedSetToSettingLocked(String settingName, int userId,
1872             Set<T> set, Function<T, String> toString) {
1873         final StringBuilder builder = new StringBuilder();
1874         for (T item : set) {
1875             final String str = (item != null ? toString.apply(item) : null);
1876             if (TextUtils.isEmpty(str)) {
1877                 continue;
1878             }
1879             if (builder.length() > 0) {
1880                 builder.append(COMPONENT_NAME_SEPARATOR);
1881             }
1882             builder.append(str);
1883         }
1884         final long identity = Binder.clearCallingIdentity();
1885         try {
1886             final String settingValue = builder.toString();
1887             Settings.Secure.putStringForUser(mContext.getContentResolver(),
1888                     settingName, TextUtils.isEmpty(settingValue) ? null : settingValue, userId);
1889         } finally {
1890             Binder.restoreCallingIdentity(identity);
1891         }
1892     }
1893 
updateServicesLocked(AccessibilityUserState userState)1894     private void updateServicesLocked(AccessibilityUserState userState) {
1895         Map<ComponentName, AccessibilityServiceConnection> componentNameToServiceMap =
1896                 userState.mComponentNameToServiceMap;
1897         boolean isUnlockingOrUnlocked = LocalServices.getService(UserManagerInternal.class)
1898                     .isUserUnlockingOrUnlocked(userState.mUserId);
1899 
1900         for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
1901             AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i);
1902             ComponentName componentName = ComponentName.unflattenFromString(
1903                     installedService.getId());
1904 
1905             AccessibilityServiceConnection service = componentNameToServiceMap.get(componentName);
1906 
1907             // Ignore non-encryption-aware services until user is unlocked
1908             if (!isUnlockingOrUnlocked && !installedService.isDirectBootAware()) {
1909                 Slog.d(LOG_TAG, "Ignoring non-encryption-aware service " + componentName);
1910                 continue;
1911             }
1912 
1913             // Skip the component since it may be in process or crashed.
1914             if (userState.getBindingServicesLocked().contains(componentName)
1915                     || userState.getCrashedServicesLocked().contains(componentName)) {
1916                 continue;
1917             }
1918             if (userState.mEnabledServices.contains(componentName)
1919                     && !mUiAutomationManager.suppressingAccessibilityServicesLocked()) {
1920                 if (service == null) {
1921                     service = new AccessibilityServiceConnection(userState, mContext, componentName,
1922                             installedService, sIdCounter++, mMainHandler, mLock, mSecurityPolicy,
1923                             this, getTraceManager(), mWindowManagerService,
1924                             getSystemActionPerformer(), mA11yWindowManager,
1925                             mActivityTaskManagerService);
1926                 } else if (userState.mBoundServices.contains(service)) {
1927                     continue;
1928                 }
1929                 service.bindLocked();
1930             } else {
1931                 if (service != null) {
1932                     service.unbindLocked();
1933                     removeShortcutTargetForUnboundServiceLocked(userState, service);
1934                 }
1935             }
1936         }
1937 
1938         final int count = userState.mBoundServices.size();
1939         mTempIntArray.clear();
1940         for (int i = 0; i < count; i++) {
1941             final ResolveInfo resolveInfo =
1942                     userState.mBoundServices.get(i).mAccessibilityServiceInfo.getResolveInfo();
1943             if (resolveInfo != null) {
1944                 mTempIntArray.add(resolveInfo.serviceInfo.applicationInfo.uid);
1945             }
1946         }
1947         // Calling out with lock held, but to lower-level services
1948         final AudioManagerInternal audioManager =
1949                 LocalServices.getService(AudioManagerInternal.class);
1950         if (audioManager != null) {
1951             audioManager.setAccessibilityServiceUids(mTempIntArray);
1952         }
1953         mActivityTaskManagerService.setAccessibilityServiceUids(mTempIntArray);
1954         updateAccessibilityEnabledSettingLocked(userState);
1955     }
1956 
scheduleUpdateClientsIfNeeded(AccessibilityUserState userState)1957     void scheduleUpdateClientsIfNeeded(AccessibilityUserState userState) {
1958         synchronized (mLock) {
1959             scheduleUpdateClientsIfNeededLocked(userState);
1960         }
1961     }
1962 
scheduleUpdateClientsIfNeededLocked(AccessibilityUserState userState)1963     private void scheduleUpdateClientsIfNeededLocked(AccessibilityUserState userState) {
1964         final int clientState = getClientStateLocked(userState);
1965         if (userState.getLastSentClientStateLocked() != clientState
1966                 && (mGlobalClients.getRegisteredCallbackCount() > 0
1967                         || userState.mUserClients.getRegisteredCallbackCount() > 0)) {
1968             userState.setLastSentClientStateLocked(clientState);
1969             mMainHandler.sendMessage(obtainMessage(
1970                     AccessibilityManagerService::sendStateToAllClients,
1971                     this, clientState, userState.mUserId));
1972         }
1973     }
1974 
sendStateToAllClients(int clientState, int userId)1975     private void sendStateToAllClients(int clientState, int userId) {
1976         sendStateToClients(clientState, mGlobalClients);
1977         sendStateToClients(clientState, userId);
1978     }
1979 
sendStateToClients(int clientState, int userId)1980     private void sendStateToClients(int clientState, int userId) {
1981         sendStateToClients(clientState, getUserState(userId).mUserClients);
1982     }
1983 
sendStateToClients(int clientState, RemoteCallbackList<IAccessibilityManagerClient> clients)1984     private void sendStateToClients(int clientState,
1985             RemoteCallbackList<IAccessibilityManagerClient> clients) {
1986         clients.broadcast(ignoreRemoteException(
1987                 client -> client.setState(clientState)));
1988     }
1989 
scheduleNotifyClientsOfServicesStateChangeLocked( AccessibilityUserState userState)1990     private void scheduleNotifyClientsOfServicesStateChangeLocked(
1991             AccessibilityUserState userState) {
1992         updateRecommendedUiTimeoutLocked(userState);
1993         mMainHandler.sendMessage(obtainMessage(
1994                 AccessibilityManagerService::sendServicesStateChanged,
1995                 this, userState.mUserClients, getRecommendedTimeoutMillisLocked(userState)));
1996     }
1997 
sendServicesStateChanged( RemoteCallbackList<IAccessibilityManagerClient> userClients, long uiTimeout)1998     private void sendServicesStateChanged(
1999             RemoteCallbackList<IAccessibilityManagerClient> userClients, long uiTimeout) {
2000         notifyClientsOfServicesStateChange(mGlobalClients, uiTimeout);
2001         notifyClientsOfServicesStateChange(userClients, uiTimeout);
2002     }
2003 
notifyClientsOfServicesStateChange( RemoteCallbackList<IAccessibilityManagerClient> clients, long uiTimeout)2004     private void notifyClientsOfServicesStateChange(
2005             RemoteCallbackList<IAccessibilityManagerClient> clients, long uiTimeout) {
2006         clients.broadcast(ignoreRemoteException(
2007                 client -> client.notifyServicesStateChanged(uiTimeout)));
2008     }
2009 
scheduleUpdateInputFilter(AccessibilityUserState userState)2010     private void scheduleUpdateInputFilter(AccessibilityUserState userState) {
2011         mMainHandler.sendMessage(obtainMessage(
2012                 AccessibilityManagerService::updateInputFilter, this, userState));
2013     }
2014 
scheduleUpdateFingerprintGestureHandling(AccessibilityUserState userState)2015     private void scheduleUpdateFingerprintGestureHandling(AccessibilityUserState userState) {
2016         mMainHandler.sendMessage(obtainMessage(
2017                 AccessibilityManagerService::updateFingerprintGestureHandling,
2018                 this, userState));
2019     }
2020 
updateInputFilter(AccessibilityUserState userState)2021     private void updateInputFilter(AccessibilityUserState userState) {
2022         if (mUiAutomationManager.suppressingAccessibilityServicesLocked()) return;
2023 
2024         boolean setInputFilter = false;
2025         AccessibilityInputFilter inputFilter = null;
2026         synchronized (mLock) {
2027             int flags = 0;
2028             if (userState.isDisplayMagnificationEnabledLocked()) {
2029                 flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
2030             }
2031             if (userState.isShortcutMagnificationEnabledLocked()) {
2032                 flags |= AccessibilityInputFilter.FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER;
2033             }
2034             if (userHasMagnificationServicesLocked(userState)) {
2035                 flags |= AccessibilityInputFilter.FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER;
2036             }
2037             // Touch exploration without accessibility makes no sense.
2038             if (userState.isHandlingAccessibilityEventsLocked()
2039                     && userState.isTouchExplorationEnabledLocked()) {
2040                 flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
2041                 if (userState.isServiceHandlesDoubleTapEnabledLocked()) {
2042                     flags |= AccessibilityInputFilter.FLAG_SERVICE_HANDLES_DOUBLE_TAP;
2043                 }
2044                 if (userState.isMultiFingerGesturesEnabledLocked()) {
2045                     flags |= AccessibilityInputFilter.FLAG_REQUEST_MULTI_FINGER_GESTURES;
2046                 }
2047                 if (userState.isTwoFingerPassthroughEnabledLocked()) {
2048                     flags |= AccessibilityInputFilter.FLAG_REQUEST_2_FINGER_PASSTHROUGH;
2049                 }
2050             }
2051             if (userState.isFilterKeyEventsEnabledLocked()) {
2052                 flags |= AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS;
2053             }
2054             if (userState.isSendMotionEventsEnabled()) {
2055                 flags |= AccessibilityInputFilter.FLAG_SEND_MOTION_EVENTS;
2056             }
2057 
2058             if (userState.isAutoclickEnabledLocked()) {
2059                 flags |= AccessibilityInputFilter.FLAG_FEATURE_AUTOCLICK;
2060             }
2061             if (userState.isPerformGesturesEnabledLocked()) {
2062                 flags |= AccessibilityInputFilter.FLAG_FEATURE_INJECT_MOTION_EVENTS;
2063             }
2064             if (flags != 0) {
2065                 if (!mHasInputFilter) {
2066                     mHasInputFilter = true;
2067                     if (mInputFilter == null) {
2068                         mInputFilter = new AccessibilityInputFilter(mContext,
2069                                 AccessibilityManagerService.this);
2070                     }
2071                     inputFilter = mInputFilter;
2072                     setInputFilter = true;
2073                 }
2074                 mInputFilter.setUserAndEnabledFeatures(userState.mUserId, flags);
2075             } else {
2076                 if (mHasInputFilter) {
2077                     mHasInputFilter = false;
2078                     mInputFilter.setUserAndEnabledFeatures(userState.mUserId, 0);
2079                     inputFilter = null;
2080                     setInputFilter = true;
2081                 }
2082             }
2083         }
2084         if (setInputFilter) {
2085             mWindowManagerService.setInputFilter(inputFilter);
2086         }
2087     }
2088 
showEnableTouchExplorationDialog(final AccessibilityServiceConnection service)2089     private void showEnableTouchExplorationDialog(final AccessibilityServiceConnection service) {
2090         synchronized (mLock) {
2091             String label = service.getServiceInfo().getResolveInfo()
2092                     .loadLabel(mContext.getPackageManager()).toString();
2093 
2094             final AccessibilityUserState userState = getCurrentUserStateLocked();
2095             if (userState.isTouchExplorationEnabledLocked()) {
2096                 return;
2097             }
2098             if (mEnableTouchExplorationDialog != null
2099                     && mEnableTouchExplorationDialog.isShowing()) {
2100                 return;
2101             }
2102             mEnableTouchExplorationDialog = new AlertDialog.Builder(mContext)
2103                 .setIconAttribute(android.R.attr.alertDialogIcon)
2104                 .setPositiveButton(android.R.string.ok, new OnClickListener() {
2105                     @Override
2106                     public void onClick(DialogInterface dialog, int which) {
2107                         // The user allowed the service to toggle touch exploration.
2108                         userState.mTouchExplorationGrantedServices.add(service.mComponentName);
2109                         persistComponentNamesToSettingLocked(
2110                                 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
2111                                 userState.mTouchExplorationGrantedServices, userState.mUserId);
2112                         // Enable touch exploration.
2113                         userState.setTouchExplorationEnabledLocked(true);
2114                         final long identity = Binder.clearCallingIdentity();
2115                         try {
2116                             Settings.Secure.putIntForUser(mContext.getContentResolver(),
2117                                     Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1,
2118                                     userState.mUserId);
2119                         } finally {
2120                             Binder.restoreCallingIdentity(identity);
2121                         }
2122                         onUserStateChangedLocked(userState);
2123                     }
2124                 })
2125                 .setNegativeButton(android.R.string.cancel, new OnClickListener() {
2126                     @Override
2127                     public void onClick(DialogInterface dialog, int which) {
2128                         dialog.dismiss();
2129                     }
2130                 })
2131                 .setTitle(R.string.enable_explore_by_touch_warning_title)
2132                 .setMessage(mContext.getString(
2133                         R.string.enable_explore_by_touch_warning_message, label))
2134                 .create();
2135              mEnableTouchExplorationDialog.getWindow().setType(
2136                      WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
2137              mEnableTouchExplorationDialog.getWindow().getAttributes().privateFlags
2138                      |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
2139              mEnableTouchExplorationDialog.setCanceledOnTouchOutside(true);
2140              mEnableTouchExplorationDialog.show();
2141         }
2142     }
2143 
2144     /**
2145      * Called when any property of the user state has changed.
2146      *
2147      * @param userState the new user state
2148      */
onUserStateChangedLocked(AccessibilityUserState userState)2149     private void onUserStateChangedLocked(AccessibilityUserState userState) {
2150         // TODO: Remove this hack
2151         mInitialized = true;
2152         updateLegacyCapabilitiesLocked(userState);
2153         updateServicesLocked(userState);
2154         updateWindowsForAccessibilityCallbackLocked(userState);
2155         updateFilterKeyEventsLocked(userState);
2156         updateTouchExplorationLocked(userState);
2157         updatePerformGesturesLocked(userState);
2158         updateMagnificationLocked(userState);
2159         scheduleUpdateFingerprintGestureHandling(userState);
2160         scheduleUpdateInputFilter(userState);
2161         updateRelevantEventsLocked(userState);
2162         scheduleUpdateClientsIfNeededLocked(userState);
2163         updateAccessibilityShortcutKeyTargetsLocked(userState);
2164         updateAccessibilityButtonTargetsLocked(userState);
2165         // Update the capabilities before the mode.
2166         updateMagnificationCapabilitiesSettingsChangeLocked(userState);
2167         updateMagnificationModeChangeSettingsLocked(userState);
2168         updateFocusAppearanceDataLocked(userState);
2169     }
2170 
updateWindowsForAccessibilityCallbackLocked(AccessibilityUserState userState)2171     private void updateWindowsForAccessibilityCallbackLocked(AccessibilityUserState userState) {
2172         // We observe windows for accessibility only if there is at least
2173         // one bound service that can retrieve window content that specified
2174         // it is interested in accessing such windows. For services that are
2175         // binding we do an update pass after each bind event, so we run this
2176         // code and register the callback if needed.
2177 
2178         boolean observingWindows = mUiAutomationManager.canRetrieveInteractiveWindowsLocked();
2179         List<AccessibilityServiceConnection> boundServices = userState.mBoundServices;
2180         final int boundServiceCount = boundServices.size();
2181         for (int i = 0; !observingWindows && (i < boundServiceCount); i++) {
2182             AccessibilityServiceConnection boundService = boundServices.get(i);
2183             if (boundService.canRetrieveInteractiveWindowsLocked()) {
2184                 userState.setAccessibilityFocusOnlyInActiveWindow(false);
2185                 observingWindows = true;
2186             }
2187         }
2188         userState.setAccessibilityFocusOnlyInActiveWindow(true);
2189 
2190         // Gets all valid displays and start tracking windows of each display if there is at least
2191         // one bound service that can retrieve window content.
2192         final ArrayList<Display> displays = getValidDisplayList();
2193         for (int i = 0; i < displays.size(); i++) {
2194             final Display display = displays.get(i);
2195             if (display != null) {
2196                 if (observingWindows) {
2197                     mA11yWindowManager.startTrackingWindows(display.getDisplayId());
2198                 } else {
2199                     mA11yWindowManager.stopTrackingWindows(display.getDisplayId());
2200                 }
2201             }
2202         }
2203     }
2204 
updateLegacyCapabilitiesLocked(AccessibilityUserState userState)2205     private void updateLegacyCapabilitiesLocked(AccessibilityUserState userState) {
2206         // Up to JB-MR1 we had a allowlist with services that can enable touch
2207         // exploration. When a service is first started we show a dialog to the
2208         // use to get a permission to allowlist the service.
2209         final int installedServiceCount = userState.mInstalledServices.size();
2210         for (int i = 0; i < installedServiceCount; i++) {
2211             AccessibilityServiceInfo serviceInfo = userState.mInstalledServices.get(i);
2212             ResolveInfo resolveInfo = serviceInfo.getResolveInfo();
2213             if ((serviceInfo.getCapabilities()
2214                         & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) == 0
2215                     && resolveInfo.serviceInfo.applicationInfo.targetSdkVersion
2216                         <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
2217                 ComponentName componentName = new ComponentName(
2218                         resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
2219                 if (userState.mTouchExplorationGrantedServices.contains(componentName)) {
2220                     serviceInfo.setCapabilities(serviceInfo.getCapabilities()
2221                             | AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION);
2222                 }
2223             }
2224         }
2225     }
2226 
updatePerformGesturesLocked(AccessibilityUserState userState)2227     private void updatePerformGesturesLocked(AccessibilityUserState userState) {
2228         final int serviceCount = userState.mBoundServices.size();
2229         for (int i = 0; i < serviceCount; i++) {
2230             AccessibilityServiceConnection service = userState.mBoundServices.get(i);
2231             if ((service.getCapabilities()
2232                     & AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES) != 0) {
2233                 userState.setPerformGesturesEnabledLocked(true);
2234                 return;
2235             }
2236         }
2237         userState.setPerformGesturesEnabledLocked(false);
2238     }
2239 
updateFilterKeyEventsLocked(AccessibilityUserState userState)2240     private void updateFilterKeyEventsLocked(AccessibilityUserState userState) {
2241         final int serviceCount = userState.mBoundServices.size();
2242         for (int i = 0; i < serviceCount; i++) {
2243             AccessibilityServiceConnection service = userState.mBoundServices.get(i);
2244             if (service.mRequestFilterKeyEvents
2245                     && (service.getCapabilities()
2246                             & AccessibilityServiceInfo
2247                             .CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) != 0) {
2248                 userState.setFilterKeyEventsEnabledLocked(true);
2249                 return;
2250             }
2251         }
2252         userState.setFilterKeyEventsEnabledLocked(false);
2253     }
2254 
readConfigurationForUserStateLocked(AccessibilityUserState userState)2255     private boolean readConfigurationForUserStateLocked(AccessibilityUserState userState) {
2256         boolean somethingChanged = readInstalledAccessibilityServiceLocked(userState);
2257         somethingChanged |= readInstalledAccessibilityShortcutLocked(userState);
2258         somethingChanged |= readEnabledAccessibilityServicesLocked(userState);
2259         somethingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState);
2260         somethingChanged |= readTouchExplorationEnabledSettingLocked(userState);
2261         somethingChanged |= readHighTextContrastEnabledSettingLocked(userState);
2262         somethingChanged |= readMagnificationEnabledSettingsLocked(userState);
2263         somethingChanged |= readAutoclickEnabledSettingLocked(userState);
2264         somethingChanged |= readAccessibilityShortcutKeySettingLocked(userState);
2265         somethingChanged |= readAccessibilityButtonTargetsLocked(userState);
2266         somethingChanged |= readAccessibilityButtonTargetComponentLocked(userState);
2267         somethingChanged |= readUserRecommendedUiTimeoutSettingsLocked(userState);
2268         somethingChanged |= readMagnificationModeLocked(userState);
2269         somethingChanged |= readMagnificationCapabilitiesLocked(userState);
2270         return somethingChanged;
2271     }
2272 
updateAccessibilityEnabledSettingLocked(AccessibilityUserState userState)2273     private void updateAccessibilityEnabledSettingLocked(AccessibilityUserState userState) {
2274         final boolean isA11yEnabled = mUiAutomationManager.isUiAutomationRunningLocked()
2275                 || userState.isHandlingAccessibilityEventsLocked();
2276         final long identity = Binder.clearCallingIdentity();
2277         try {
2278             Settings.Secure.putIntForUser(mContext.getContentResolver(),
2279                     Settings.Secure.ACCESSIBILITY_ENABLED,
2280                     (isA11yEnabled) ? 1 : 0,
2281                     userState.mUserId);
2282         } finally {
2283             Binder.restoreCallingIdentity(identity);
2284         }
2285     }
2286 
readTouchExplorationEnabledSettingLocked(AccessibilityUserState userState)2287     private boolean readTouchExplorationEnabledSettingLocked(AccessibilityUserState userState) {
2288         final boolean touchExplorationEnabled = Settings.Secure.getIntForUser(
2289                 mContext.getContentResolver(),
2290                 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId) == 1;
2291         if (touchExplorationEnabled != userState.isTouchExplorationEnabledLocked()) {
2292             userState.setTouchExplorationEnabledLocked(touchExplorationEnabled);
2293             return true;
2294         }
2295         return false;
2296     }
2297 
readMagnificationEnabledSettingsLocked(AccessibilityUserState userState)2298     private boolean readMagnificationEnabledSettingsLocked(AccessibilityUserState userState) {
2299         final boolean displayMagnificationEnabled = Settings.Secure.getIntForUser(
2300                 mContext.getContentResolver(),
2301                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
2302                 0, userState.mUserId) == 1;
2303         if ((displayMagnificationEnabled != userState.isDisplayMagnificationEnabledLocked())) {
2304             userState.setDisplayMagnificationEnabledLocked(displayMagnificationEnabled);
2305             return true;
2306         }
2307         return false;
2308     }
2309 
readAutoclickEnabledSettingLocked(AccessibilityUserState userState)2310     private boolean readAutoclickEnabledSettingLocked(AccessibilityUserState userState) {
2311         final boolean autoclickEnabled = Settings.Secure.getIntForUser(
2312                 mContext.getContentResolver(),
2313                 Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED,
2314                 0, userState.mUserId) == 1;
2315         if (autoclickEnabled != userState.isAutoclickEnabledLocked()) {
2316             userState.setAutoclickEnabledLocked(autoclickEnabled);
2317             return true;
2318         }
2319         return false;
2320     }
2321 
readHighTextContrastEnabledSettingLocked(AccessibilityUserState userState)2322     private boolean readHighTextContrastEnabledSettingLocked(AccessibilityUserState userState) {
2323         final boolean highTextContrastEnabled = Settings.Secure.getIntForUser(
2324                 mContext.getContentResolver(),
2325                 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, 0,
2326                 userState.mUserId) == 1;
2327         if (highTextContrastEnabled != userState.isTextHighContrastEnabledLocked()) {
2328             userState.setTextHighContrastEnabledLocked(highTextContrastEnabled);
2329             return true;
2330         }
2331         return false;
2332     }
2333 
updateTouchExplorationLocked(AccessibilityUserState userState)2334     private void updateTouchExplorationLocked(AccessibilityUserState userState) {
2335         boolean touchExplorationEnabled = mUiAutomationManager.isTouchExplorationEnabledLocked();
2336         boolean serviceHandlesDoubleTapEnabled = false;
2337         boolean requestMultiFingerGestures = false;
2338         boolean requestTwoFingerPassthrough = false;
2339         boolean sendMotionEvents = false;
2340         final int serviceCount = userState.mBoundServices.size();
2341         for (int i = 0; i < serviceCount; i++) {
2342             AccessibilityServiceConnection service = userState.mBoundServices.get(i);
2343             if (canRequestAndRequestsTouchExplorationLocked(service, userState)) {
2344                 touchExplorationEnabled = true;
2345                 serviceHandlesDoubleTapEnabled = service.isServiceHandlesDoubleTapEnabled();
2346                 requestMultiFingerGestures = service.isMultiFingerGesturesEnabled();
2347                 requestTwoFingerPassthrough = service.isTwoFingerPassthroughEnabled();
2348                 sendMotionEvents = service.isSendMotionEventsEnabled();
2349                 break;
2350             }
2351         }
2352         if (touchExplorationEnabled != userState.isTouchExplorationEnabledLocked()) {
2353             userState.setTouchExplorationEnabledLocked(touchExplorationEnabled);
2354             final long identity = Binder.clearCallingIdentity();
2355             try {
2356                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
2357                         Settings.Secure.TOUCH_EXPLORATION_ENABLED, touchExplorationEnabled ? 1 : 0,
2358                         userState.mUserId);
2359             } finally {
2360                 Binder.restoreCallingIdentity(identity);
2361             }
2362         }
2363         userState.setServiceHandlesDoubleTapLocked(serviceHandlesDoubleTapEnabled);
2364         userState.setMultiFingerGesturesLocked(requestMultiFingerGestures);
2365         userState.setTwoFingerPassthroughLocked(requestTwoFingerPassthrough);
2366         userState.setSendMotionEventsEnabled(sendMotionEvents);
2367     }
2368 
readAccessibilityShortcutKeySettingLocked(AccessibilityUserState userState)2369     private boolean readAccessibilityShortcutKeySettingLocked(AccessibilityUserState userState) {
2370         final String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
2371                 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, userState.mUserId);
2372         final Set<String> targetsFromSetting = new ArraySet<>();
2373         readColonDelimitedStringToSet(settingValue, str -> str, targetsFromSetting, false);
2374         // Fall back to device's default a11y service, only when setting is never updated.
2375         if (settingValue == null) {
2376             final String defaultService = mContext.getString(
2377                     R.string.config_defaultAccessibilityService);
2378             if (!TextUtils.isEmpty(defaultService)) {
2379                 targetsFromSetting.add(defaultService);
2380             }
2381         }
2382 
2383         final Set<String> currentTargets =
2384                 userState.getShortcutTargetsLocked(ACCESSIBILITY_SHORTCUT_KEY);
2385         if (targetsFromSetting.equals(currentTargets)) {
2386             return false;
2387         }
2388         currentTargets.clear();
2389         currentTargets.addAll(targetsFromSetting);
2390         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
2391         return true;
2392     }
2393 
readAccessibilityButtonTargetsLocked(AccessibilityUserState userState)2394     private boolean readAccessibilityButtonTargetsLocked(AccessibilityUserState userState) {
2395         final Set<String> targetsFromSetting = new ArraySet<>();
2396         readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
2397                 userState.mUserId, str -> str, targetsFromSetting);
2398 
2399         final Set<String> currentTargets =
2400                 userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON);
2401         if (targetsFromSetting.equals(currentTargets)) {
2402             return false;
2403         }
2404         currentTargets.clear();
2405         currentTargets.addAll(targetsFromSetting);
2406         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
2407         return true;
2408     }
2409 
readAccessibilityButtonTargetComponentLocked(AccessibilityUserState userState)2410     private boolean readAccessibilityButtonTargetComponentLocked(AccessibilityUserState userState) {
2411         final String componentId = Settings.Secure.getStringForUser(mContext.getContentResolver(),
2412                 Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, userState.mUserId);
2413         if (TextUtils.isEmpty(componentId)) {
2414             if (userState.getTargetAssignedToAccessibilityButton() == null) {
2415                 return false;
2416             }
2417             userState.setTargetAssignedToAccessibilityButton(null);
2418             return true;
2419         }
2420         if (componentId.equals(userState.getTargetAssignedToAccessibilityButton())) {
2421             return false;
2422         }
2423         userState.setTargetAssignedToAccessibilityButton(componentId);
2424         return true;
2425     }
2426 
readUserRecommendedUiTimeoutSettingsLocked(AccessibilityUserState userState)2427     private boolean readUserRecommendedUiTimeoutSettingsLocked(AccessibilityUserState userState) {
2428         final int nonInteractiveUiTimeout = Settings.Secure.getIntForUser(
2429                 mContext.getContentResolver(),
2430                 Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS, 0,
2431                 userState.mUserId);
2432         final int interactiveUiTimeout = Settings.Secure.getIntForUser(
2433                 mContext.getContentResolver(),
2434                 Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, 0,
2435                 userState.mUserId);
2436         if (nonInteractiveUiTimeout != userState.getUserNonInteractiveUiTimeoutLocked()
2437                 || interactiveUiTimeout != userState.getUserInteractiveUiTimeoutLocked()) {
2438             userState.setUserNonInteractiveUiTimeoutLocked(nonInteractiveUiTimeout);
2439             userState.setUserInteractiveUiTimeoutLocked(interactiveUiTimeout);
2440             scheduleNotifyClientsOfServicesStateChangeLocked(userState);
2441             return true;
2442         }
2443         return false;
2444     }
2445 
2446     /**
2447      * Check if the target that will be enabled by the accessibility shortcut key is installed.
2448      * If it isn't, remove it from the list and associated setting so a side loaded service can't
2449      * spoof the package name of the default service.
2450      */
updateAccessibilityShortcutKeyTargetsLocked(AccessibilityUserState userState)2451     private void updateAccessibilityShortcutKeyTargetsLocked(AccessibilityUserState userState) {
2452         final Set<String> currentTargets =
2453                 userState.getShortcutTargetsLocked(ACCESSIBILITY_SHORTCUT_KEY);
2454         final int lastSize = currentTargets.size();
2455         if (lastSize == 0) {
2456             return;
2457         }
2458         currentTargets.removeIf(
2459                 name -> !userState.isShortcutTargetInstalledLocked(name));
2460         if (lastSize == currentTargets.size()) {
2461             return;
2462         }
2463 
2464         // Update setting key with new value.
2465         persistColonDelimitedSetToSettingLocked(
2466                 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
2467                 userState.mUserId, currentTargets, str -> str);
2468         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
2469     }
2470 
canRequestAndRequestsTouchExplorationLocked( AccessibilityServiceConnection service, AccessibilityUserState userState)2471     private boolean canRequestAndRequestsTouchExplorationLocked(
2472             AccessibilityServiceConnection service, AccessibilityUserState userState) {
2473         // Service not ready or cannot request the feature - well nothing to do.
2474         if (!service.canReceiveEventsLocked() || !service.mRequestTouchExplorationMode) {
2475             return false;
2476         }
2477         if (service.getServiceInfo().getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion
2478                 <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
2479             // Up to JB-MR1 we had a allowlist with services that can enable touch
2480             // exploration. When a service is first started we show a dialog to the
2481             // use to get a permission to allowlist the service.
2482             if (userState.mTouchExplorationGrantedServices.contains(service.mComponentName)) {
2483                 return true;
2484             } else if (mEnableTouchExplorationDialog == null
2485                     || !mEnableTouchExplorationDialog.isShowing()) {
2486                 mMainHandler.sendMessage(obtainMessage(
2487                         AccessibilityManagerService::showEnableTouchExplorationDialog,
2488                         this, service));
2489             }
2490         } else {
2491             // Starting in JB-MR2 we request an accessibility service to declare
2492             // certain capabilities in its meta-data to allow it to enable the
2493             // corresponding features.
2494             if ((service.getCapabilities()
2495                     & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) != 0) {
2496                 return true;
2497             }
2498         }
2499         return false;
2500     }
2501 
updateMagnificationLocked(AccessibilityUserState userState)2502     private void updateMagnificationLocked(AccessibilityUserState userState) {
2503         if (userState.mUserId != mCurrentUserId) {
2504             return;
2505         }
2506 
2507         if (mUiAutomationManager.suppressingAccessibilityServicesLocked()
2508                 && mMagnificationController.isFullScreenMagnificationControllerInitialized()) {
2509             getFullScreenMagnificationController().unregisterAll();
2510             return;
2511         }
2512 
2513         // Get all valid displays and register them if global magnification is enabled.
2514         // We would skip overlay display because it uses overlay window to simulate secondary
2515         // displays in one display. It's not a real display and there's no input events for it.
2516         final ArrayList<Display> displays = getValidDisplayList();
2517         if (userState.isDisplayMagnificationEnabledLocked()
2518                 || userState.isShortcutMagnificationEnabledLocked()) {
2519             for (int i = 0; i < displays.size(); i++) {
2520                 final Display display = displays.get(i);
2521                 getFullScreenMagnificationController().register(display.getDisplayId());
2522             }
2523             return;
2524         }
2525 
2526         // Register if display has listening magnification services.
2527         for (int i = 0; i < displays.size(); i++) {
2528             final Display display = displays.get(i);
2529             final int displayId = display.getDisplayId();
2530             if (userHasListeningMagnificationServicesLocked(userState, displayId)) {
2531                 getFullScreenMagnificationController().register(displayId);
2532             } else if (mMagnificationController.isFullScreenMagnificationControllerInitialized()) {
2533                 getFullScreenMagnificationController().unregister(displayId);
2534             }
2535         }
2536     }
2537 
updateWindowMagnificationConnectionIfNeeded(AccessibilityUserState userState)2538     private void updateWindowMagnificationConnectionIfNeeded(AccessibilityUserState userState) {
2539         final boolean connect = (userState.isShortcutMagnificationEnabledLocked()
2540                 || userState.isDisplayMagnificationEnabledLocked())
2541                 && (userState.getMagnificationCapabilitiesLocked()
2542                 != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
2543         getWindowMagnificationMgr().requestConnection(connect);
2544     }
2545 
2546     /**
2547      * Returns whether the specified user has any services that are capable of
2548      * controlling magnification.
2549      */
userHasMagnificationServicesLocked(AccessibilityUserState userState)2550     private boolean userHasMagnificationServicesLocked(AccessibilityUserState userState) {
2551         final List<AccessibilityServiceConnection> services = userState.mBoundServices;
2552         for (int i = 0, count = services.size(); i < count; i++) {
2553             final AccessibilityServiceConnection service = services.get(i);
2554             if (mSecurityPolicy.canControlMagnification(service)) {
2555                 return true;
2556             }
2557         }
2558         return false;
2559     }
2560 
2561     /**
2562      * Returns whether the specified user has any services that are capable of
2563      * controlling magnification and are actively listening for magnification updates.
2564      */
userHasListeningMagnificationServicesLocked(AccessibilityUserState userState, int displayId)2565     private boolean userHasListeningMagnificationServicesLocked(AccessibilityUserState userState,
2566             int displayId) {
2567         final List<AccessibilityServiceConnection> services = userState.mBoundServices;
2568         for (int i = 0, count = services.size(); i < count; i++) {
2569             final AccessibilityServiceConnection service = services.get(i);
2570             if (mSecurityPolicy.canControlMagnification(service)
2571                     && service.isMagnificationCallbackEnabled(displayId)) {
2572                 return true;
2573             }
2574         }
2575         return false;
2576     }
2577 
updateFingerprintGestureHandling(AccessibilityUserState userState)2578     private void updateFingerprintGestureHandling(AccessibilityUserState userState) {
2579         final List<AccessibilityServiceConnection> services;
2580         synchronized (mLock) {
2581             services = userState.mBoundServices;
2582             if ((mFingerprintGestureDispatcher == null)
2583                     &&  mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
2584                 // Only create the controller when a service wants to use the feature
2585                 int numServices = services.size();
2586                 for (int i = 0; i < numServices; i++) {
2587                     if (services.get(i).isCapturingFingerprintGestures()) {
2588                         IFingerprintService service = null;
2589                         final long identity = Binder.clearCallingIdentity();
2590                         try {
2591                             service = IFingerprintService.Stub.asInterface(
2592                                     ServiceManager.getService(Context.FINGERPRINT_SERVICE));
2593                         } finally {
2594                             Binder.restoreCallingIdentity(identity);
2595                         }
2596                         if (service != null) {
2597                             mFingerprintGestureDispatcher = new FingerprintGestureDispatcher(
2598                                     service, mContext.getResources(), mLock);
2599                             break;
2600                         }
2601                     }
2602                 }
2603             }
2604         }
2605         if (mFingerprintGestureDispatcher != null) {
2606             mFingerprintGestureDispatcher.updateClientList(services);
2607         }
2608     }
2609 
2610     /**
2611      * 1) Update accessibility button availability to accessibility services.
2612      * 2) Check if the target that will be enabled by the accessibility button is installed.
2613      *    If it isn't, remove it from the list and associated setting so a side loaded service can't
2614      *    spoof the package name of the default service.
2615      */
updateAccessibilityButtonTargetsLocked(AccessibilityUserState userState)2616     private void updateAccessibilityButtonTargetsLocked(AccessibilityUserState userState) {
2617         // Update accessibility button availability.
2618         for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
2619             final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
2620             if (service.mRequestAccessibilityButton) {
2621                 service.notifyAccessibilityButtonAvailabilityChangedLocked(
2622                         service.isAccessibilityButtonAvailableLocked(userState));
2623             }
2624         }
2625 
2626         final Set<String> currentTargets =
2627                 userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON);
2628         final int lastSize = currentTargets.size();
2629         if (lastSize == 0) {
2630             return;
2631         }
2632         currentTargets.removeIf(
2633                 name -> !userState.isShortcutTargetInstalledLocked(name));
2634         if (lastSize == currentTargets.size()) {
2635             return;
2636         }
2637 
2638         // Update setting key with new value.
2639         persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
2640                 userState.mUserId, currentTargets, str -> str);
2641         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
2642     }
2643 
2644     /**
2645      * 1) Check if the service assigned to accessibility button target sdk version > Q.
2646      *    If it isn't, remove it from the list and associated setting.
2647      *    (It happens when an accessibility service package is downgraded.)
2648      * 2) For a service targeting sdk version > Q and requesting a11y button, it should be in the
2649      *    enabled list if's assigned to a11y button.
2650      *    (It happens when an accessibility service package is same graded, and updated requesting
2651      *     a11y button flag)
2652      * 3) Check if an enabled service targeting sdk version > Q and requesting a11y button is
2653      *    assigned to a shortcut. If it isn't, assigns it to the accessibility button.
2654      *    (It happens when an enabled accessibility service package is upgraded.)
2655      *
2656      * @param packageName The package name to check, or {@code null} to check all services.
2657      * @param restoreFromSdkInt The target sdk version of the restored source device, or {@code 0}
2658      *                          if the caller is not related to the restore.
2659      */
migrateAccessibilityButtonSettingsIfNecessaryLocked( AccessibilityUserState userState, @Nullable String packageName, int restoreFromSdkInt)2660     private void migrateAccessibilityButtonSettingsIfNecessaryLocked(
2661             AccessibilityUserState userState, @Nullable String packageName, int restoreFromSdkInt) {
2662         // No need to migrate settings if they are restored from a version after Q.
2663         if (restoreFromSdkInt > Build.VERSION_CODES.Q) {
2664             return;
2665         }
2666         final Set<String> buttonTargets =
2667                 userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON);
2668         int lastSize = buttonTargets.size();
2669         buttonTargets.removeIf(name -> {
2670             if (packageName != null && name != null && !name.contains(packageName)) {
2671                 return false;
2672             }
2673             final ComponentName componentName = ComponentName.unflattenFromString(name);
2674             if (componentName == null) {
2675                 return false;
2676             }
2677             final AccessibilityServiceInfo serviceInfo =
2678                     userState.getInstalledServiceInfoLocked(componentName);
2679             if (serviceInfo == null) {
2680                 return false;
2681             }
2682             if (serviceInfo.getResolveInfo().serviceInfo.applicationInfo
2683                     .targetSdkVersion <= Build.VERSION_CODES.Q) {
2684                 // A11y services targeting sdk version <= Q should not be in the list.
2685                 Slog.v(LOG_TAG, "Legacy service " + componentName
2686                         + " should not in the button");
2687                 return true;
2688             }
2689             final boolean requestA11yButton = (serviceInfo.flags
2690                     & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
2691             if (requestA11yButton && !userState.mEnabledServices.contains(componentName)) {
2692                 // An a11y service targeting sdk version > Q and request A11y button and is assigned
2693                 // to a11y btn should be in the enabled list.
2694                 Slog.v(LOG_TAG, "Service requesting a11y button and be assigned to the button"
2695                         + componentName + " should be enabled state");
2696                 return true;
2697             }
2698             return false;
2699         });
2700         boolean changed = (lastSize != buttonTargets.size());
2701         lastSize = buttonTargets.size();
2702 
2703         final Set<String> shortcutKeyTargets =
2704                 userState.getShortcutTargetsLocked(ACCESSIBILITY_SHORTCUT_KEY);
2705         userState.mEnabledServices.forEach(componentName -> {
2706             if (packageName != null && componentName != null
2707                     && !packageName.equals(componentName.getPackageName())) {
2708                 return;
2709             }
2710             final AccessibilityServiceInfo serviceInfo =
2711                     userState.getInstalledServiceInfoLocked(componentName);
2712             if (serviceInfo == null) {
2713                 return;
2714             }
2715             final boolean requestA11yButton = (serviceInfo.flags
2716                     & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
2717             if (!(serviceInfo.getResolveInfo().serviceInfo.applicationInfo
2718                     .targetSdkVersion > Build.VERSION_CODES.Q && requestA11yButton)) {
2719                 return;
2720             }
2721             final String serviceName = componentName.flattenToString();
2722             if (TextUtils.isEmpty(serviceName)) {
2723                 return;
2724             }
2725             if (doesShortcutTargetsStringContain(buttonTargets, serviceName)
2726                     || doesShortcutTargetsStringContain(shortcutKeyTargets, serviceName)) {
2727                 return;
2728             }
2729             // For enabled a11y services targeting sdk version > Q and requesting a11y button should
2730             // be assigned to a shortcut.
2731             Slog.v(LOG_TAG, "A enabled service requesting a11y button " + componentName
2732                     + " should be assign to the button or shortcut.");
2733             buttonTargets.add(serviceName);
2734         });
2735         changed |= (lastSize != buttonTargets.size());
2736         if (!changed) {
2737             return;
2738         }
2739 
2740         // Update setting key with new value.
2741         persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
2742                 userState.mUserId, buttonTargets, str -> str);
2743         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
2744     }
2745 
2746     /**
2747      * Remove the shortcut target for the unbound service which is requesting accessibility button
2748      * and targeting sdk > Q from the accessibility button and shortcut.
2749      *
2750      * @param userState The accessibility user state.
2751      * @param service The unbound service.
2752      */
removeShortcutTargetForUnboundServiceLocked(AccessibilityUserState userState, AccessibilityServiceConnection service)2753     private void removeShortcutTargetForUnboundServiceLocked(AccessibilityUserState userState,
2754             AccessibilityServiceConnection service) {
2755         if (!service.mRequestAccessibilityButton
2756                 || service.getServiceInfo().getResolveInfo().serviceInfo.applicationInfo
2757                 .targetSdkVersion <= Build.VERSION_CODES.Q) {
2758             return;
2759         }
2760         final ComponentName serviceName = service.getComponentName();
2761         if (userState.removeShortcutTargetLocked(ACCESSIBILITY_SHORTCUT_KEY, serviceName)) {
2762             final Set<String> currentTargets = userState.getShortcutTargetsLocked(
2763                     ACCESSIBILITY_SHORTCUT_KEY);
2764             persistColonDelimitedSetToSettingLocked(
2765                     Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
2766                     userState.mUserId, currentTargets, str -> str);
2767         }
2768         if (userState.removeShortcutTargetLocked(ACCESSIBILITY_BUTTON, serviceName)) {
2769             final Set<String> currentTargets = userState.getShortcutTargetsLocked(
2770                     ACCESSIBILITY_BUTTON);
2771             persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
2772                     userState.mUserId, currentTargets, str -> str);
2773         }
2774     }
2775 
updateRecommendedUiTimeoutLocked(AccessibilityUserState userState)2776     private void updateRecommendedUiTimeoutLocked(AccessibilityUserState userState) {
2777         int newNonInteractiveUiTimeout = userState.getUserNonInteractiveUiTimeoutLocked();
2778         int newInteractiveUiTimeout = userState.getUserInteractiveUiTimeoutLocked();
2779         // read from a11y services if user does not specify value
2780         if (newNonInteractiveUiTimeout == 0 || newInteractiveUiTimeout == 0) {
2781             int serviceNonInteractiveUiTimeout = 0;
2782             int serviceInteractiveUiTimeout = 0;
2783             final List<AccessibilityServiceConnection> services = userState.mBoundServices;
2784             for (int i = 0; i < services.size(); i++) {
2785                 int timeout = services.get(i).getServiceInfo().getInteractiveUiTimeoutMillis();
2786                 if (serviceInteractiveUiTimeout < timeout) {
2787                     serviceInteractiveUiTimeout = timeout;
2788                 }
2789                 timeout = services.get(i).getServiceInfo().getNonInteractiveUiTimeoutMillis();
2790                 if (serviceNonInteractiveUiTimeout < timeout) {
2791                     serviceNonInteractiveUiTimeout = timeout;
2792                 }
2793             }
2794             if (newNonInteractiveUiTimeout == 0) {
2795                 newNonInteractiveUiTimeout = serviceNonInteractiveUiTimeout;
2796             }
2797             if (newInteractiveUiTimeout == 0) {
2798                 newInteractiveUiTimeout = serviceInteractiveUiTimeout;
2799             }
2800         }
2801         userState.setNonInteractiveUiTimeoutLocked(newNonInteractiveUiTimeout);
2802         userState.setInteractiveUiTimeoutLocked(newInteractiveUiTimeout);
2803     }
2804 
2805     @GuardedBy("mLock")
2806     @Override
getCompatibleMagnificationSpecLocked(int windowId)2807     public MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) {
2808         if (mTraceManager.isA11yTracingEnabled()) {
2809             mTraceManager.logTrace(LOG_TAG + ".getCompatibleMagnificationSpecLocked",
2810                     "windowId=" + windowId);
2811         }
2812 
2813         IBinder windowToken = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(
2814                 mCurrentUserId, windowId);
2815         if (windowToken != null) {
2816             return mWindowManagerService.getCompatibleMagnificationSpecForWindow(
2817                     windowToken);
2818         }
2819         return null;
2820     }
2821 
2822     @Override
getKeyEventDispatcher()2823     public KeyEventDispatcher getKeyEventDispatcher() {
2824         if (mTraceManager.isA11yTracingEnabled()) {
2825             mTraceManager.logTrace(LOG_TAG + ".getKeyEventDispatcher");
2826         }
2827 
2828         if (mKeyEventDispatcher == null) {
2829             mKeyEventDispatcher = new KeyEventDispatcher(
2830                     mMainHandler, MainHandler.MSG_SEND_KEY_EVENT_TO_INPUT_FILTER, mLock,
2831                     mPowerManager);
2832         }
2833         return mKeyEventDispatcher;
2834     }
2835 
2836     @Override
2837     @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
getPendingIntentActivity(Context context, int requestCode, Intent intent, int flags)2838     public PendingIntent getPendingIntentActivity(Context context, int requestCode, Intent intent,
2839             int flags) {
2840         if (mTraceManager.isA11yTracingEnabled()) {
2841             mTraceManager.logTrace(LOG_TAG + ".getPendingIntentActivity",
2842                     "context=" + context + ";requestCode=" + requestCode + ";intent=" + intent
2843                             + ";flags=" + flags);
2844         }
2845 
2846 
2847         return PendingIntent.getActivity(context, requestCode, intent, flags);
2848     }
2849 
2850     /**
2851      * AIDL-exposed method to be called when the accessibility shortcut key is enabled. Requires
2852      * permission to write secure settings, since someone with that permission can enable
2853      * accessibility services themselves.
2854      *
2855      * @param targetName The flattened {@link ComponentName} string or the class name of a system
2856      *        class implementing a supported accessibility feature, or {@code null} if there's no
2857      *        specified target.
2858      */
2859     @Override
performAccessibilityShortcut(String targetName)2860     public void performAccessibilityShortcut(String targetName) {
2861         if (mTraceManager.isA11yTracingEnabled()) {
2862             mTraceManager.logTrace(LOG_TAG + ".performAccessibilityShortcut",
2863                     "targetName=" + targetName);
2864         }
2865 
2866         if ((UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID)
2867                 && (mContext.checkCallingPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
2868                 != PackageManager.PERMISSION_GRANTED)) {
2869             throw new SecurityException(
2870                     "performAccessibilityShortcut requires the MANAGE_ACCESSIBILITY permission");
2871         }
2872         mMainHandler.sendMessage(obtainMessage(
2873                 AccessibilityManagerService::performAccessibilityShortcutInternal, this,
2874                 Display.DEFAULT_DISPLAY, ACCESSIBILITY_SHORTCUT_KEY, targetName));
2875     }
2876 
2877     /**
2878      * Perform the accessibility shortcut action.
2879      *
2880      * @param shortcutType The shortcut type.
2881      * @param displayId The display id of the accessibility button.
2882      * @param targetName The flattened {@link ComponentName} string or the class name of a system
2883      *        class implementing a supported accessibility feature, or {@code null} if there's no
2884      *        specified target.
2885      */
performAccessibilityShortcutInternal(int displayId, @ShortcutType int shortcutType, @Nullable String targetName)2886     private void performAccessibilityShortcutInternal(int displayId,
2887             @ShortcutType int shortcutType, @Nullable String targetName) {
2888         final List<String> shortcutTargets = getAccessibilityShortcutTargetsInternal(shortcutType);
2889         if (shortcutTargets.isEmpty()) {
2890             Slog.d(LOG_TAG, "No target to perform shortcut, shortcutType=" + shortcutType);
2891             return;
2892         }
2893         // In case the caller specified a target name
2894         if (targetName != null && !doesShortcutTargetsStringContain(shortcutTargets, targetName)) {
2895             Slog.v(LOG_TAG, "Perform shortcut failed, invalid target name:" + targetName);
2896             targetName = null;
2897         }
2898         if (targetName == null) {
2899             // In case there are many targets assigned to the given shortcut.
2900             if (shortcutTargets.size() > 1) {
2901                 showAccessibilityTargetsSelection(displayId, shortcutType);
2902                 return;
2903             }
2904             targetName = shortcutTargets.get(0);
2905         }
2906         // In case user assigned magnification to the given shortcut.
2907         if (targetName.equals(MAGNIFICATION_CONTROLLER_NAME)) {
2908             final boolean enabled = !getFullScreenMagnificationController().isMagnifying(displayId);
2909             logAccessibilityShortcutActivated(mContext, MAGNIFICATION_COMPONENT_NAME, shortcutType,
2910                     enabled);
2911             sendAccessibilityButtonToInputFilter(displayId);
2912             return;
2913         }
2914         final ComponentName targetComponentName = ComponentName.unflattenFromString(targetName);
2915         if (targetComponentName == null) {
2916             Slog.d(LOG_TAG, "Perform shortcut failed, invalid target name:" + targetName);
2917             return;
2918         }
2919         // In case user assigned an accessibility framework feature to the given shortcut.
2920         if (performAccessibilityFrameworkFeature(targetComponentName, shortcutType)) {
2921             return;
2922         }
2923         // In case user assigned an accessibility shortcut target to the given shortcut.
2924         if (performAccessibilityShortcutTargetActivity(displayId, targetComponentName)) {
2925             logAccessibilityShortcutActivated(mContext, targetComponentName, shortcutType);
2926             return;
2927         }
2928         // in case user assigned an accessibility service to the given shortcut.
2929         if (performAccessibilityShortcutTargetService(
2930                 displayId, shortcutType, targetComponentName)) {
2931             return;
2932         }
2933     }
2934 
performAccessibilityFrameworkFeature(ComponentName assignedTarget, @ShortcutType int shortcutType)2935     private boolean performAccessibilityFrameworkFeature(ComponentName assignedTarget,
2936             @ShortcutType int shortcutType) {
2937         final Map<ComponentName, ToggleableFrameworkFeatureInfo> frameworkFeatureMap =
2938                 AccessibilityShortcutController.getFrameworkShortcutFeaturesMap();
2939         if (!frameworkFeatureMap.containsKey(assignedTarget)) {
2940             return false;
2941         }
2942         // Toggle the requested framework feature
2943         final ToggleableFrameworkFeatureInfo featureInfo = frameworkFeatureMap.get(assignedTarget);
2944         final SettingStringHelper setting = new SettingStringHelper(mContext.getContentResolver(),
2945                 featureInfo.getSettingKey(), mCurrentUserId);
2946         // Assuming that the default state will be to have the feature off
2947         if (!TextUtils.equals(featureInfo.getSettingOnValue(), setting.read())) {
2948             logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType,
2949                     /* serviceEnabled= */ true);
2950             setting.write(featureInfo.getSettingOnValue());
2951         } else {
2952             logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType,
2953                     /* serviceEnabled= */ false);
2954             setting.write(featureInfo.getSettingOffValue());
2955         }
2956         return true;
2957     }
2958 
performAccessibilityShortcutTargetActivity(int displayId, ComponentName assignedTarget)2959     private boolean performAccessibilityShortcutTargetActivity(int displayId,
2960             ComponentName assignedTarget) {
2961         synchronized (mLock) {
2962             final AccessibilityUserState userState = getCurrentUserStateLocked();
2963             for (int i = 0; i < userState.mInstalledShortcuts.size(); i++) {
2964                 final AccessibilityShortcutInfo shortcutInfo = userState.mInstalledShortcuts.get(i);
2965                 if (!shortcutInfo.getComponentName().equals(assignedTarget)) {
2966                     continue;
2967                 }
2968                 launchShortcutTargetActivity(displayId, assignedTarget);
2969                 return true;
2970             }
2971         }
2972         return false;
2973     }
2974 
2975     /**
2976      * Perform accessibility service shortcut action.
2977      *
2978      * 1) For {@link AccessibilityManager#ACCESSIBILITY_BUTTON} type and services targeting sdk
2979      *    version <= Q: callbacks to accessibility service if service is bounded and requests
2980      *    accessibility button.
2981      * 2) For {@link AccessibilityManager#ACCESSIBILITY_SHORTCUT_KEY} type and service targeting sdk
2982      *    version <= Q: turns on / off the accessibility service.
2983      * 3) For {@link AccessibilityManager#ACCESSIBILITY_SHORTCUT_KEY} type and service targeting sdk
2984      *    version > Q and request accessibility button: turn on the accessibility service if it's
2985      *    not in the enabled state.
2986      *    (It'll happen when a service is disabled and assigned to shortcut then upgraded.)
2987      * 4) For services targeting sdk version > Q:
2988      *    a) Turns on / off the accessibility service, if service does not request accessibility
2989      *       button.
2990      *    b) Callbacks to accessibility service if service is bounded and requests accessibility
2991      *       button.
2992      */
performAccessibilityShortcutTargetService(int displayId, @ShortcutType int shortcutType, ComponentName assignedTarget)2993     private boolean performAccessibilityShortcutTargetService(int displayId,
2994             @ShortcutType int shortcutType, ComponentName assignedTarget) {
2995         synchronized (mLock) {
2996             final AccessibilityUserState userState = getCurrentUserStateLocked();
2997             final AccessibilityServiceInfo installedServiceInfo =
2998                     userState.getInstalledServiceInfoLocked(assignedTarget);
2999             if (installedServiceInfo == null) {
3000                 Slog.d(LOG_TAG, "Perform shortcut failed, invalid component name:"
3001                         + assignedTarget);
3002                 return false;
3003             }
3004 
3005             final AccessibilityServiceConnection serviceConnection =
3006                     userState.getServiceConnectionLocked(assignedTarget);
3007             final int targetSdk = installedServiceInfo.getResolveInfo()
3008                     .serviceInfo.applicationInfo.targetSdkVersion;
3009             final boolean requestA11yButton = (installedServiceInfo.flags
3010                     & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
3011             // Turns on / off the accessibility service
3012             if ((targetSdk <= Build.VERSION_CODES.Q && shortcutType == ACCESSIBILITY_SHORTCUT_KEY)
3013                     || (targetSdk > Build.VERSION_CODES.Q && !requestA11yButton)) {
3014                 if (serviceConnection == null) {
3015                     logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType,
3016                             /* serviceEnabled= */ true);
3017                     enableAccessibilityServiceLocked(assignedTarget, mCurrentUserId);
3018 
3019                 } else {
3020                     logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType,
3021                             /* serviceEnabled= */ false);
3022                     disableAccessibilityServiceLocked(assignedTarget, mCurrentUserId);
3023                 }
3024                 return true;
3025             }
3026             if (shortcutType == ACCESSIBILITY_SHORTCUT_KEY && targetSdk > Build.VERSION_CODES.Q
3027                     && requestA11yButton) {
3028                 if (!userState.getEnabledServicesLocked().contains(assignedTarget)) {
3029                     enableAccessibilityServiceLocked(assignedTarget, mCurrentUserId);
3030                     return true;
3031                 }
3032             }
3033             // Callbacks to a11y service if it's bounded and requests a11y button.
3034             if (serviceConnection == null
3035                     || !userState.mBoundServices.contains(serviceConnection)
3036                     || !serviceConnection.mRequestAccessibilityButton) {
3037                 Slog.d(LOG_TAG, "Perform shortcut failed, service is not ready:"
3038                         + assignedTarget);
3039                 return false;
3040             }
3041             // ServiceConnection means service enabled.
3042             logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType,
3043                     /* serviceEnabled= */ true);
3044             serviceConnection.notifyAccessibilityButtonClickedLocked(displayId);
3045             return true;
3046         }
3047     }
3048 
3049     @Override
getAccessibilityShortcutTargets(@hortcutType int shortcutType)3050     public List<String> getAccessibilityShortcutTargets(@ShortcutType int shortcutType) {
3051         if (mTraceManager.isA11yTracingEnabled()) {
3052             mTraceManager.logTrace(LOG_TAG + ".getAccessibilityShortcutTargets",
3053                     "shortcutType=" + shortcutType);
3054         }
3055 
3056         if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
3057                 != PackageManager.PERMISSION_GRANTED) {
3058             throw new SecurityException(
3059                     "getAccessibilityShortcutService requires the MANAGE_ACCESSIBILITY permission");
3060         }
3061         return getAccessibilityShortcutTargetsInternal(shortcutType);
3062     }
3063 
getAccessibilityShortcutTargetsInternal(@hortcutType int shortcutType)3064     private List<String> getAccessibilityShortcutTargetsInternal(@ShortcutType int shortcutType) {
3065         synchronized (mLock) {
3066             final AccessibilityUserState userState = getCurrentUserStateLocked();
3067             final ArrayList<String> shortcutTargets = new ArrayList<>(
3068                     userState.getShortcutTargetsLocked(shortcutType));
3069             if (shortcutType != ACCESSIBILITY_BUTTON) {
3070                 return shortcutTargets;
3071             }
3072             // Adds legacy a11y services requesting a11y button into the list.
3073             for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
3074                 final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
3075                 if (!service.mRequestAccessibilityButton
3076                         || service.getServiceInfo().getResolveInfo().serviceInfo.applicationInfo
3077                         .targetSdkVersion > Build.VERSION_CODES.Q) {
3078                     continue;
3079                 }
3080                 final String serviceName = service.getComponentName().flattenToString();
3081                 if (!TextUtils.isEmpty(serviceName)) {
3082                     shortcutTargets.add(serviceName);
3083                 }
3084             }
3085             return shortcutTargets;
3086         }
3087     }
3088 
3089     /**
3090      * Enables accessibility service specified by {@param componentName} for the {@param userId}.
3091      */
enableAccessibilityServiceLocked(ComponentName componentName, int userId)3092     private void enableAccessibilityServiceLocked(ComponentName componentName, int userId) {
3093         mTempComponentNameSet.clear();
3094         readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
3095                 userId, mTempComponentNameSet);
3096         mTempComponentNameSet.add(componentName);
3097         persistComponentNamesToSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
3098                 mTempComponentNameSet, userId);
3099 
3100         AccessibilityUserState userState = getUserStateLocked(userId);
3101         if (userState.mEnabledServices.add(componentName)) {
3102             onUserStateChangedLocked(userState);
3103         }
3104     }
3105 
3106     /**
3107      * Disables accessibility service specified by {@param componentName} for the {@param userId}.
3108      */
disableAccessibilityServiceLocked(ComponentName componentName, int userId)3109     private void disableAccessibilityServiceLocked(ComponentName componentName, int userId) {
3110         mTempComponentNameSet.clear();
3111         readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
3112                 userId, mTempComponentNameSet);
3113         mTempComponentNameSet.remove(componentName);
3114         persistComponentNamesToSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
3115                 mTempComponentNameSet, userId);
3116 
3117         AccessibilityUserState userState = getUserStateLocked(userId);
3118         if (userState.mEnabledServices.remove(componentName)) {
3119             onUserStateChangedLocked(userState);
3120         }
3121     }
3122 
3123     @Override
sendAccessibilityEventForCurrentUserLocked(AccessibilityEvent event)3124     public void sendAccessibilityEventForCurrentUserLocked(AccessibilityEvent event) {
3125         if (mTraceManager.isA11yTracingEnabled()) {
3126             mTraceManager.logTrace(LOG_TAG + ".sendAccessibilityEventForCurrentUserLocked",
3127                     "event=" + event);
3128         }
3129 
3130         sendAccessibilityEventLocked(event, mCurrentUserId);
3131     }
3132 
sendAccessibilityEventLocked(AccessibilityEvent event, int userId)3133     private void sendAccessibilityEventLocked(AccessibilityEvent event, int userId) {
3134         // Resync to avoid calling out with the lock held
3135         event.setEventTime(SystemClock.uptimeMillis());
3136         mMainHandler.sendMessage(obtainMessage(
3137                 AccessibilityManagerService::sendAccessibilityEvent,
3138                 this, event, userId));
3139     }
3140 
3141     /**
3142      * AIDL-exposed method. System only.
3143      * Inform accessibility that a fingerprint gesture was performed
3144      *
3145      * @param gestureKeyCode The key code corresponding to the fingerprint gesture.
3146      * @return {@code true} if accessibility consumes the fingerprint gesture, {@code false} if it
3147      * doesn't.
3148      */
3149     @Override
sendFingerprintGesture(int gestureKeyCode)3150     public boolean sendFingerprintGesture(int gestureKeyCode) {
3151         if (mTraceManager.isA11yTracingEnabled()) {
3152             mTraceManager.logTrace(LOG_TAG + ".sendFingerprintGesture",
3153                     "gestureKeyCode=" + gestureKeyCode);
3154         }
3155 
3156         synchronized(mLock) {
3157             if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
3158                 throw new SecurityException("Only SYSTEM can call sendFingerprintGesture");
3159             }
3160         }
3161         if (mFingerprintGestureDispatcher == null) {
3162             return false;
3163         }
3164         return mFingerprintGestureDispatcher.onFingerprintGesture(gestureKeyCode);
3165     }
3166 
3167     /**
3168      * AIDL-exposed method. System only.
3169      * Gets accessibility window id from window token.
3170      *
3171      * @param windowToken Window token to get accessibility window id.
3172      * @return Accessibility window id for the window token. Returns -1 if no such token is
3173      *   registered.
3174      */
3175     @Override
getAccessibilityWindowId(@ullable IBinder windowToken)3176     public int getAccessibilityWindowId(@Nullable IBinder windowToken) {
3177         if (mTraceManager.isA11yTracingEnabled()) {
3178             mTraceManager.logTrace(LOG_TAG + ".getAccessibilityWindowId",
3179                     "windowToken=" + windowToken);
3180         }
3181 
3182         synchronized (mLock) {
3183             if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
3184                 throw new SecurityException("Only SYSTEM can call getAccessibilityWindowId");
3185             }
3186 
3187             return mA11yWindowManager.findWindowIdLocked(mCurrentUserId, windowToken);
3188         }
3189     }
3190 
3191     /**
3192      * Get the recommended timeout of interactive controls and non-interactive controls.
3193      *
3194      * @return A long for pair of {@code int}s. First integer for interactive one, and second
3195      * integer for non-interactive one.
3196      */
3197     @Override
getRecommendedTimeoutMillis()3198     public long getRecommendedTimeoutMillis() {
3199         if (mTraceManager.isA11yTracingEnabled()) {
3200             mTraceManager.logTrace(LOG_TAG + ".getRecommendedTimeoutMillis");
3201         }
3202 
3203         synchronized(mLock) {
3204             final AccessibilityUserState userState = getCurrentUserStateLocked();
3205             return getRecommendedTimeoutMillisLocked(userState);
3206         }
3207     }
3208 
getRecommendedTimeoutMillisLocked(AccessibilityUserState userState)3209     private long getRecommendedTimeoutMillisLocked(AccessibilityUserState userState) {
3210         return IntPair.of(userState.getInteractiveUiTimeoutLocked(),
3211                 userState.getNonInteractiveUiTimeoutLocked());
3212     }
3213 
3214     @Override
setWindowMagnificationConnection( IWindowMagnificationConnection connection)3215     public void setWindowMagnificationConnection(
3216             IWindowMagnificationConnection connection) throws RemoteException {
3217         if (mTraceManager.isA11yTracingEnabled()) {
3218             mTraceManager.logTrace(LOG_TAG + ".setWindowMagnificationConnection",
3219                     "connection=" + connection);
3220         }
3221 
3222         mSecurityPolicy.enforceCallingOrSelfPermission(
3223                 android.Manifest.permission.STATUS_BAR_SERVICE);
3224 
3225         getWindowMagnificationMgr().setConnection(connection);
3226     }
3227 
3228     /**
3229      * Getter of {@link WindowMagnificationManager}.
3230      *
3231      * @return WindowMagnificationManager
3232      */
getWindowMagnificationMgr()3233     public WindowMagnificationManager getWindowMagnificationMgr() {
3234         synchronized (mLock) {
3235             return mMagnificationController.getWindowMagnificationMgr();
3236         }
3237     }
3238 
3239     /**
3240      * Getter of {@link MagnificationController}.
3241      *
3242      * @return MagnificationController
3243      */
getMagnificationController()3244     MagnificationController getMagnificationController() {
3245         synchronized (mLock) {
3246             return mMagnificationController;
3247         }
3248     }
3249 
3250     @Override
associateEmbeddedHierarchy(@onNull IBinder host, @NonNull IBinder embedded)3251     public void associateEmbeddedHierarchy(@NonNull IBinder host, @NonNull IBinder embedded) {
3252         if (mTraceManager.isA11yTracingEnabled()) {
3253             mTraceManager.logTrace(LOG_TAG + ".associateEmbeddedHierarchy",
3254                     "host=" + host + ";embedded=" + embedded);
3255         }
3256 
3257         synchronized (mLock) {
3258             mA11yWindowManager.associateEmbeddedHierarchyLocked(host, embedded);
3259         }
3260     }
3261 
3262     @Override
disassociateEmbeddedHierarchy(@onNull IBinder token)3263     public void disassociateEmbeddedHierarchy(@NonNull IBinder token) {
3264         if (mTraceManager.isA11yTracingEnabled()) {
3265             mTraceManager.logTrace(LOG_TAG + ".disassociateEmbeddedHierarchy", "token=" + token);
3266         }
3267 
3268         synchronized (mLock) {
3269             mA11yWindowManager.disassociateEmbeddedHierarchyLocked(token);
3270         }
3271     }
3272 
3273     /**
3274      * Gets the stroke width of the focus rectangle.
3275      * @return The stroke width.
3276      */
getFocusStrokeWidth()3277     public int getFocusStrokeWidth() {
3278         synchronized (mLock) {
3279             final AccessibilityUserState userState = getCurrentUserStateLocked();
3280 
3281             return userState.getFocusStrokeWidthLocked();
3282         }
3283     }
3284 
3285     /**
3286      * Gets the color of the focus rectangle.
3287      * @return The color.
3288      */
getFocusColor()3289     public int getFocusColor() {
3290         synchronized (mLock) {
3291             final AccessibilityUserState userState = getCurrentUserStateLocked();
3292 
3293             return userState.getFocusColorLocked();
3294         }
3295     }
3296 
3297     @Override
dump(FileDescriptor fd, final PrintWriter pw, String[] args)3298     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
3299         if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
3300         synchronized (mLock) {
3301             pw.println("ACCESSIBILITY MANAGER (dumpsys accessibility)");
3302             pw.println();
3303             pw.append("currentUserId=").append(String.valueOf(mCurrentUserId));
3304             pw.println();
3305             pw.append("hasWindowMagnificationConnection=").append(
3306                     String.valueOf(getWindowMagnificationMgr().isConnected()));
3307             pw.println();
3308             final int userCount = mUserStates.size();
3309             for (int i = 0; i < userCount; i++) {
3310                 mUserStates.valueAt(i).dump(fd, pw, args);
3311             }
3312             if (mUiAutomationManager.isUiAutomationRunningLocked()) {
3313                 mUiAutomationManager.dumpUiAutomationService(fd, pw, args);
3314                 pw.println();
3315             }
3316             mA11yWindowManager.dump(fd, pw, args);
3317             pw.println("Global client list info:{");
3318             mGlobalClients.dump(pw, "    Client list ");
3319             pw.println("    Registered clients:{");
3320             for (int i = 0; i < mGlobalClients.getRegisteredCallbackCount(); i++) {
3321                 AccessibilityManagerService.Client client = (AccessibilityManagerService.Client)
3322                         mGlobalClients.getRegisteredCallbackCookie(i);
3323                 pw.append(Arrays.toString(client.mPackageNames));
3324             }
3325         }
3326     }
3327 
3328     //TODO remove after refactoring KeyEventDispatcherTest
3329     final class MainHandler extends Handler {
3330         public static final int MSG_SEND_KEY_EVENT_TO_INPUT_FILTER = 8;
3331 
MainHandler(Looper looper)3332         public MainHandler(Looper looper) {
3333             super(looper);
3334         }
3335 
3336         @Override
handleMessage(Message msg)3337         public void handleMessage(Message msg) {
3338             if (msg.what == MSG_SEND_KEY_EVENT_TO_INPUT_FILTER) {
3339                 KeyEvent event = (KeyEvent) msg.obj;
3340                 final int policyFlags = msg.arg1;
3341                 synchronized (mLock) {
3342                     if (mHasInputFilter && mInputFilter != null) {
3343                         mInputFilter.sendInputEvent(event, policyFlags);
3344                     }
3345                 }
3346                 event.recycle();
3347             }
3348         }
3349     }
3350 
3351     @Override
getFullScreenMagnificationController()3352     public FullScreenMagnificationController getFullScreenMagnificationController() {
3353         if (mTraceManager.isA11yTracingEnabled()) {
3354             mTraceManager.logTrace(LOG_TAG + ".getFullScreenMagnificationController");
3355         }
3356         synchronized (mLock) {
3357             return mMagnificationController.getFullScreenMagnificationController();
3358         }
3359     }
3360 
3361     @Override
onClientChangeLocked(boolean serviceInfoChanged)3362     public void onClientChangeLocked(boolean serviceInfoChanged) {
3363         if (mTraceManager.isA11yTracingEnabled()) {
3364             mTraceManager.logTrace(LOG_TAG + ".onClientChangeLocked",
3365                     "serviceInfoChanged=" + serviceInfoChanged);
3366         }
3367 
3368         AccessibilityUserState userState = getUserStateLocked(mCurrentUserId);
3369         onUserStateChangedLocked(userState);
3370         if (serviceInfoChanged) {
3371             scheduleNotifyClientsOfServicesStateChangeLocked(userState);
3372         }
3373     }
3374 
3375     @Override
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)3376     public void onShellCommand(FileDescriptor in, FileDescriptor out,
3377             FileDescriptor err, String[] args, ShellCallback callback,
3378             ResultReceiver resultReceiver) {
3379         new AccessibilityShellCommand(this, mSystemActionPerformer).exec(this, in, out, err, args,
3380                 callback, resultReceiver);
3381     }
3382 
3383     private final class InteractionBridge {
3384         private final ComponentName COMPONENT_NAME =
3385                 new ComponentName("com.android.server.accessibility", "InteractionBridge");
3386 
3387         private final Display mDefaultDisplay;
3388         private final int mConnectionId;
3389         private final AccessibilityInteractionClient mClient;
3390 
InteractionBridge()3391         public InteractionBridge() {
3392             final AccessibilityServiceInfo info = new AccessibilityServiceInfo();
3393             info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
3394             info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
3395             info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
3396             final AccessibilityUserState userState;
3397             synchronized (mLock) {
3398                 userState = getCurrentUserStateLocked();
3399             }
3400             AccessibilityServiceConnection service = new AccessibilityServiceConnection(
3401                     userState, mContext,
3402                     COMPONENT_NAME, info, sIdCounter++, mMainHandler, mLock, mSecurityPolicy,
3403                     AccessibilityManagerService.this,
3404                     AccessibilityManagerService.this.getTraceManager(), mWindowManagerService,
3405                     getSystemActionPerformer(), mA11yWindowManager, mActivityTaskManagerService) {
3406                 @Override
3407                 public boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) {
3408                     return true;
3409                 }
3410             };
3411 
3412             mConnectionId = service.mId;
3413 
3414             mClient = AccessibilityInteractionClient.getInstance(mContext);
3415             mClient.addConnection(mConnectionId, service);
3416 
3417             //TODO: (multi-display) We need to support multiple displays.
3418             DisplayManager displayManager = (DisplayManager)
3419                     mContext.getSystemService(Context.DISPLAY_SERVICE);
3420             mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
3421         }
3422 
3423         /**
3424          * Gets a point within the accessibility focused node where we can send down and up events
3425          * to perform a click.
3426          *
3427          * @param outPoint The click point to populate.
3428          * @return Whether accessibility a click point was found and set.
3429          */
3430         // TODO: (multi-display) Make sure this works for multiple displays.
getAccessibilityFocusClickPointInScreen(Point outPoint)3431         boolean getAccessibilityFocusClickPointInScreen(Point outPoint) {
3432             return getInteractionBridge()
3433                     .getAccessibilityFocusClickPointInScreenNotLocked(outPoint);
3434         }
3435 
3436     /**
3437          * Perform an accessibility action on the view that currently has accessibility focus.
3438          * Has no effect if no item has accessibility focus, if the item with accessibility
3439          * focus does not expose the specified action, or if the action fails.
3440          *
3441          * @param action The action to perform.
3442          *
3443          * @return {@code true} if the action was performed. {@code false} if it was not.
3444          */
performActionOnAccessibilityFocusedItemNotLocked( AccessibilityNodeInfo.AccessibilityAction action)3445         public boolean performActionOnAccessibilityFocusedItemNotLocked(
3446                 AccessibilityNodeInfo.AccessibilityAction action) {
3447             AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked();
3448             if ((focus == null) || !focus.getActionList().contains(action)) {
3449                 return false;
3450             }
3451             return focus.performAction(action.getId());
3452         }
3453 
getAccessibilityFocusClickPointInScreenNotLocked(Point outPoint)3454         public boolean getAccessibilityFocusClickPointInScreenNotLocked(Point outPoint) {
3455             AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked();
3456             if (focus == null) {
3457                 return false;
3458             }
3459 
3460             synchronized (mLock) {
3461                 Rect boundsInScreen = mTempRect;
3462                 focus.getBoundsInScreen(boundsInScreen);
3463 
3464                 // Apply magnification if needed.
3465                 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId());
3466                 if (spec != null && !spec.isNop()) {
3467                     boundsInScreen.offset((int) -spec.offsetX, (int) -spec.offsetY);
3468                     boundsInScreen.scale(1 / spec.scale);
3469                 }
3470 
3471                 // Clip to the window bounds.
3472                 Rect windowBounds = mTempRect1;
3473                 getWindowBounds(focus.getWindowId(), windowBounds);
3474                 if (!boundsInScreen.intersect(windowBounds)) {
3475                     return false;
3476                 }
3477 
3478                 // Clip to the screen bounds.
3479                 Point screenSize = mTempPoint;
3480                 mDefaultDisplay.getRealSize(screenSize);
3481                 if (!boundsInScreen.intersect(0, 0, screenSize.x, screenSize.y)) {
3482                     return false;
3483                 }
3484 
3485                 outPoint.set(boundsInScreen.centerX(), boundsInScreen.centerY());
3486             }
3487 
3488             return true;
3489         }
3490 
getAccessibilityFocusNotLocked()3491         private AccessibilityNodeInfo getAccessibilityFocusNotLocked() {
3492             final int focusedWindowId;
3493             synchronized (mLock) {
3494                 focusedWindowId = mA11yWindowManager.getFocusedWindowId(
3495                         AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
3496                 if (focusedWindowId == AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
3497                     return null;
3498                 }
3499             }
3500             return getAccessibilityFocusNotLocked(focusedWindowId);
3501         }
3502 
getAccessibilityFocusNotLocked(int windowId)3503         private AccessibilityNodeInfo getAccessibilityFocusNotLocked(int windowId) {
3504             return mClient.findFocus(mConnectionId,
3505                     windowId, AccessibilityNodeInfo.ROOT_NODE_ID,
3506                     AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
3507         }
3508     }
3509 
3510     /**
3511      * Gets all currently valid logical displays.
3512      *
3513      * @return An array list containing all valid logical displays.
3514      */
getValidDisplayList()3515     public ArrayList<Display> getValidDisplayList() {
3516         return mA11yDisplayListener.getValidDisplayList();
3517     }
3518 
3519     /**
3520      * A Utility class to handle display state.
3521      */
3522     public class AccessibilityDisplayListener implements DisplayManager.DisplayListener {
3523         private final DisplayManager mDisplayManager;
3524         private final ArrayList<Display> mDisplaysList = new ArrayList<>();
3525         private int mSystemUiUid = 0;
3526 
AccessibilityDisplayListener(Context context, MainHandler handler)3527         AccessibilityDisplayListener(Context context, MainHandler handler) {
3528             mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
3529             mDisplayManager.registerDisplayListener(this, handler);
3530             initializeDisplayList();
3531 
3532             final PackageManagerInternal pm =
3533                     LocalServices.getService(PackageManagerInternal.class);
3534             if (pm != null) {
3535                 mSystemUiUid = pm.getPackageUid(pm.getSystemUiServiceComponent().getPackageName(),
3536                         PackageManager.MATCH_SYSTEM_ONLY, mCurrentUserId);
3537             }
3538         }
3539 
getValidDisplayList()3540         ArrayList<Display> getValidDisplayList() {
3541             synchronized (mLock) {
3542                 return mDisplaysList;
3543             }
3544         }
3545 
initializeDisplayList()3546         private void initializeDisplayList() {
3547             final Display[] displays = mDisplayManager.getDisplays();
3548             synchronized (mLock) {
3549                 mDisplaysList.clear();
3550                 for (int i = 0; i < displays.length; i++) {
3551                     // Exclude overlay virtual displays. The display list is for A11yInputFilter
3552                     // to create event handler per display. The events should be handled by the
3553                     // display which is overlaid by it.
3554                     final Display display = displays[i];
3555                     if (isValidDisplay(display)) {
3556                         mDisplaysList.add(display);
3557                     }
3558                 }
3559             }
3560         }
3561 
3562         @Override
onDisplayAdded(int displayId)3563         public void onDisplayAdded(int displayId) {
3564             final Display display = mDisplayManager.getDisplay(displayId);
3565             if (!isValidDisplay(display)) {
3566                 return;
3567             }
3568 
3569             synchronized (mLock) {
3570                 mDisplaysList.add(display);
3571                 if (mInputFilter != null) {
3572                     mInputFilter.onDisplayChanged();
3573                 }
3574                 AccessibilityUserState userState = getCurrentUserStateLocked();
3575                 if (displayId != Display.DEFAULT_DISPLAY) {
3576                     final List<AccessibilityServiceConnection> services = userState.mBoundServices;
3577                     for (int i = 0; i < services.size(); i++) {
3578                         AccessibilityServiceConnection boundClient = services.get(i);
3579                         boundClient.onDisplayAdded(displayId);
3580                     }
3581                 }
3582                 updateMagnificationLocked(userState);
3583                 updateWindowsForAccessibilityCallbackLocked(userState);
3584             }
3585         }
3586 
3587         @Override
onDisplayRemoved(int displayId)3588         public void onDisplayRemoved(int displayId) {
3589             synchronized (mLock) {
3590                 if (!removeDisplayFromList(displayId)) {
3591                     return;
3592                 }
3593                 if (mInputFilter != null) {
3594                     mInputFilter.onDisplayChanged();
3595                 }
3596                 AccessibilityUserState userState = getCurrentUserStateLocked();
3597                 if (displayId != Display.DEFAULT_DISPLAY) {
3598                     final List<AccessibilityServiceConnection> services = userState.mBoundServices;
3599                     for (int i = 0; i < services.size(); i++) {
3600                         AccessibilityServiceConnection boundClient = services.get(i);
3601                         boundClient.onDisplayRemoved(displayId);
3602                     }
3603                 }
3604             }
3605             mMagnificationController.onDisplayRemoved(displayId);
3606             mA11yWindowManager.stopTrackingWindows(displayId);
3607         }
3608 
3609         @GuardedBy("mLock")
removeDisplayFromList(int displayId)3610         private boolean removeDisplayFromList(int displayId) {
3611             for (int i = 0; i < mDisplaysList.size(); i++) {
3612                 if (mDisplaysList.get(i).getDisplayId() == displayId) {
3613                     mDisplaysList.remove(i);
3614                     return true;
3615                 }
3616             }
3617             return false;
3618         }
3619 
3620         @Override
onDisplayChanged(int displayId)3621         public void onDisplayChanged(int displayId) {
3622             /* do nothing */
3623         }
3624 
isValidDisplay(@ullable Display display)3625         private boolean isValidDisplay(@Nullable Display display) {
3626             if (display == null || display.getType() == Display.TYPE_OVERLAY) {
3627                 return false;
3628             }
3629             // Private virtual displays are created by the ap and is not allowed to access by other
3630             // aps. We assume we could ignore them.
3631             // The exceptional case is for bubbles. Because the bubbles use the activityView, and
3632             // the virtual display of the activityView is private, so if the owner UID of the
3633             // private virtual display is the one of system ui which creates the virtual display of
3634             // bubbles, then this private virtual display should track the windows.
3635             if (display.getType() == Display.TYPE_VIRTUAL
3636                     && (display.getFlags() & Display.FLAG_PRIVATE) != 0
3637                     && display.getOwnerUid() != mSystemUiUid) {
3638                 return false;
3639             }
3640             return true;
3641         }
3642     }
3643 
3644     /** Represents an {@link AccessibilityManager} */
3645     class Client {
3646         final IAccessibilityManagerClient mCallback;
3647         final String[] mPackageNames;
3648         int mLastSentRelevantEventTypes;
3649 
Client(IAccessibilityManagerClient callback, int clientUid, AccessibilityUserState userState)3650         private Client(IAccessibilityManagerClient callback, int clientUid,
3651                 AccessibilityUserState userState) {
3652             mCallback = callback;
3653             mPackageNames = mPackageManager.getPackagesForUid(clientUid);
3654             synchronized (mLock) {
3655                 mLastSentRelevantEventTypes = computeRelevantEventTypesLocked(userState, this);
3656             }
3657         }
3658     }
3659 
3660     private final class AccessibilityContentObserver extends ContentObserver {
3661 
3662         private final Uri mTouchExplorationEnabledUri = Settings.Secure.getUriFor(
3663                 Settings.Secure.TOUCH_EXPLORATION_ENABLED);
3664 
3665         private final Uri mDisplayMagnificationEnabledUri = Settings.Secure.getUriFor(
3666                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
3667 
3668         private final Uri mAutoclickEnabledUri = Settings.Secure.getUriFor(
3669                 Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED);
3670 
3671         private final Uri mEnabledAccessibilityServicesUri = Settings.Secure.getUriFor(
3672                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
3673 
3674         private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure
3675                 .getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
3676 
3677         private final Uri mHighTextContrastUri = Settings.Secure.getUriFor(
3678                 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED);
3679 
3680         private final Uri mAccessibilitySoftKeyboardModeUri = Settings.Secure.getUriFor(
3681                 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
3682 
3683         private final Uri mShowImeWithHardKeyboardUri = Settings.Secure.getUriFor(
3684                 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
3685 
3686         private final Uri mAccessibilityShortcutServiceIdUri = Settings.Secure.getUriFor(
3687                 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
3688 
3689         private final Uri mAccessibilityButtonComponentIdUri = Settings.Secure.getUriFor(
3690                 Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT);
3691 
3692         private final Uri mAccessibilityButtonTargetsUri = Settings.Secure.getUriFor(
3693                 Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
3694 
3695         private final Uri mUserNonInteractiveUiTimeoutUri = Settings.Secure.getUriFor(
3696                 Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS);
3697 
3698         private final Uri mUserInteractiveUiTimeoutUri = Settings.Secure.getUriFor(
3699                 Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS);
3700 
3701         private final Uri mMagnificationModeUri = Settings.Secure.getUriFor(
3702                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE);
3703 
3704         private final Uri mMagnificationCapabilityUri = Settings.Secure.getUriFor(
3705                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY);
3706 
AccessibilityContentObserver(Handler handler)3707         public AccessibilityContentObserver(Handler handler) {
3708             super(handler);
3709         }
3710 
register(ContentResolver contentResolver)3711         public void register(ContentResolver contentResolver) {
3712             contentResolver.registerContentObserver(mTouchExplorationEnabledUri,
3713                     false, this, UserHandle.USER_ALL);
3714             contentResolver.registerContentObserver(mDisplayMagnificationEnabledUri,
3715                     false, this, UserHandle.USER_ALL);
3716             contentResolver.registerContentObserver(mAutoclickEnabledUri,
3717                     false, this, UserHandle.USER_ALL);
3718             contentResolver.registerContentObserver(mEnabledAccessibilityServicesUri,
3719                     false, this, UserHandle.USER_ALL);
3720             contentResolver.registerContentObserver(
3721                     mTouchExplorationGrantedAccessibilityServicesUri,
3722                     false, this, UserHandle.USER_ALL);
3723             contentResolver.registerContentObserver(
3724                     mHighTextContrastUri, false, this, UserHandle.USER_ALL);
3725             contentResolver.registerContentObserver(
3726                     mAccessibilitySoftKeyboardModeUri, false, this, UserHandle.USER_ALL);
3727             contentResolver.registerContentObserver(
3728                     mShowImeWithHardKeyboardUri, false, this, UserHandle.USER_ALL);
3729             contentResolver.registerContentObserver(
3730                     mAccessibilityShortcutServiceIdUri, false, this, UserHandle.USER_ALL);
3731             contentResolver.registerContentObserver(
3732                     mAccessibilityButtonComponentIdUri, false, this, UserHandle.USER_ALL);
3733             contentResolver.registerContentObserver(
3734                     mAccessibilityButtonTargetsUri, false, this, UserHandle.USER_ALL);
3735             contentResolver.registerContentObserver(
3736                     mUserNonInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL);
3737             contentResolver.registerContentObserver(
3738                     mUserInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL);
3739             contentResolver.registerContentObserver(
3740                     mMagnificationModeUri, false, this, UserHandle.USER_ALL);
3741             contentResolver.registerContentObserver(
3742                     mMagnificationCapabilityUri, false, this, UserHandle.USER_ALL);
3743         }
3744 
3745         @Override
onChange(boolean selfChange, Uri uri)3746         public void onChange(boolean selfChange, Uri uri) {
3747             synchronized (mLock) {
3748                 // Profiles share the accessibility state of the parent. Therefore,
3749                 // we are checking for changes only the parent settings.
3750                 AccessibilityUserState userState = getCurrentUserStateLocked();
3751 
3752                 if (mTouchExplorationEnabledUri.equals(uri)) {
3753                     if (readTouchExplorationEnabledSettingLocked(userState)) {
3754                         onUserStateChangedLocked(userState);
3755                     }
3756                 } else if (mDisplayMagnificationEnabledUri.equals(uri)) {
3757                     if (readMagnificationEnabledSettingsLocked(userState)) {
3758                         onUserStateChangedLocked(userState);
3759                     }
3760                 } else if (mAutoclickEnabledUri.equals(uri)) {
3761                     if (readAutoclickEnabledSettingLocked(userState)) {
3762                         onUserStateChangedLocked(userState);
3763                     }
3764                 } else if (mEnabledAccessibilityServicesUri.equals(uri)) {
3765                     if (readEnabledAccessibilityServicesLocked(userState)) {
3766                         mSecurityPolicy.onEnabledServicesChangedLocked(userState.mUserId,
3767                                 userState.mEnabledServices);
3768                         userState.updateCrashedServicesIfNeededLocked();
3769                         onUserStateChangedLocked(userState);
3770                     }
3771                 } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) {
3772                     if (readTouchExplorationGrantedAccessibilityServicesLocked(userState)) {
3773                         onUserStateChangedLocked(userState);
3774                     }
3775                 } else if (mHighTextContrastUri.equals(uri)) {
3776                     if (readHighTextContrastEnabledSettingLocked(userState)) {
3777                         onUserStateChangedLocked(userState);
3778                     }
3779                 } else if (mAccessibilitySoftKeyboardModeUri.equals(uri)
3780                         || mShowImeWithHardKeyboardUri.equals(uri)) {
3781                     userState.reconcileSoftKeyboardModeWithSettingsLocked();
3782                 } else if (mAccessibilityShortcutServiceIdUri.equals(uri)) {
3783                     if (readAccessibilityShortcutKeySettingLocked(userState)) {
3784                         onUserStateChangedLocked(userState);
3785                     }
3786                 } else if (mAccessibilityButtonComponentIdUri.equals(uri)) {
3787                     if (readAccessibilityButtonTargetComponentLocked(userState)) {
3788                         onUserStateChangedLocked(userState);
3789                     }
3790                 } else if (mAccessibilityButtonTargetsUri.equals(uri)) {
3791                     if (readAccessibilityButtonTargetsLocked(userState)) {
3792                         onUserStateChangedLocked(userState);
3793                     }
3794                 } else if (mUserNonInteractiveUiTimeoutUri.equals(uri)
3795                         || mUserInteractiveUiTimeoutUri.equals(uri)) {
3796                     readUserRecommendedUiTimeoutSettingsLocked(userState);
3797                 } else if (mMagnificationModeUri.equals(uri)) {
3798                     if (readMagnificationModeLocked(userState)) {
3799                         updateMagnificationModeChangeSettingsLocked(userState);
3800                     }
3801                 } else if (mMagnificationCapabilityUri.equals(uri)) {
3802                     if (readMagnificationCapabilitiesLocked(userState)) {
3803                         updateMagnificationCapabilitiesSettingsChangeLocked(userState);
3804                     }
3805                 }
3806             }
3807         }
3808     }
3809 
updateMagnificationCapabilitiesSettingsChangeLocked( AccessibilityUserState userState)3810     private void updateMagnificationCapabilitiesSettingsChangeLocked(
3811             AccessibilityUserState userState) {
3812         if (fallBackMagnificationModeSettingsLocked(userState)) {
3813             updateMagnificationModeChangeSettingsLocked(userState);
3814         }
3815         updateWindowMagnificationConnectionIfNeeded(userState);
3816         // Remove magnification button UI when the magnification capability is not all mode or
3817         // magnification is disabled.
3818         if (!(userState.isDisplayMagnificationEnabledLocked()
3819                 || userState.isShortcutMagnificationEnabledLocked())
3820                 || userState.getMagnificationCapabilitiesLocked()
3821                 != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) {
3822             final ArrayList<Display> displays = getValidDisplayList();
3823             for (int i = 0; i < displays.size(); i++) {
3824                 final int displayId = displays.get(i).getDisplayId();
3825                 getWindowMagnificationMgr().removeMagnificationButton(displayId);
3826             }
3827         }
3828     }
3829 
fallBackMagnificationModeSettingsLocked(AccessibilityUserState userState)3830     private boolean fallBackMagnificationModeSettingsLocked(AccessibilityUserState userState) {
3831         if (userState.isValidMagnificationModeLocked()) {
3832             return false;
3833         }
3834         Slog.w(LOG_TAG, "invalid magnification mode:" + userState.getMagnificationModeLocked());
3835         final int capabilities = userState.getMagnificationCapabilitiesLocked();
3836         userState.setMagnificationModeLocked(capabilities);
3837         persistMagnificationModeSettingLocked(capabilities);
3838         return true;
3839     }
3840 
persistMagnificationModeSettingLocked(int mode)3841     private void persistMagnificationModeSettingLocked(int mode) {
3842         BackgroundThread.getHandler().post(() -> {
3843             final long identity = Binder.clearCallingIdentity();
3844             try {
3845                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
3846                         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, mode, mCurrentUserId);
3847             } finally {
3848                 Binder.restoreCallingIdentity(identity);
3849             }
3850         });
3851     }
3852 
3853     //TODO: support multi-display.
3854     /**
3855      * Gets the magnification mode of the specified display.
3856      *
3857      * @param displayId The logical displayId.
3858      * @return magnification mode. It's either ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN or
3859      * ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW.
3860      */
getMagnificationMode(int displayId)3861     public int getMagnificationMode(int displayId) {
3862         synchronized (mLock) {
3863             return getCurrentUserStateLocked().getMagnificationModeLocked();
3864         }
3865     }
3866 
readMagnificationModeLocked(AccessibilityUserState userState)3867     private boolean readMagnificationModeLocked(AccessibilityUserState userState) {
3868         final int magnificationMode = Settings.Secure.getIntForUser(
3869                 mContext.getContentResolver(),
3870                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE,
3871                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, userState.mUserId);
3872         if (magnificationMode != userState.getMagnificationModeLocked()) {
3873             userState.setMagnificationModeLocked(magnificationMode);
3874             return true;
3875         }
3876         return false;
3877     }
3878 
readMagnificationCapabilitiesLocked(AccessibilityUserState userState)3879     private boolean readMagnificationCapabilitiesLocked(AccessibilityUserState userState) {
3880         final int capabilities = Settings.Secure.getIntForUser(
3881                 mContext.getContentResolver(),
3882                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY,
3883                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, userState.mUserId);
3884         if (capabilities != userState.getMagnificationCapabilitiesLocked()) {
3885             userState.setMagnificationCapabilitiesLocked(capabilities);
3886             mMagnificationController.setMagnificationCapabilities(capabilities);
3887             return true;
3888         }
3889         return false;
3890     }
3891 
3892     @Override
setGestureDetectionPassthroughRegion(int displayId, Region region)3893     public void setGestureDetectionPassthroughRegion(int displayId, Region region) {
3894         if (mTraceManager.isA11yTracingEnabled()) {
3895             mTraceManager.logTrace(LOG_TAG + ".setGestureDetectionPassthroughRegion",
3896                     "displayId=" + displayId + ";region=" + region);
3897         }
3898 
3899         mMainHandler.sendMessage(
3900                 obtainMessage(
3901                         AccessibilityManagerService::setGestureDetectionPassthroughRegionInternal,
3902                         this,
3903                         displayId,
3904                         region));
3905     }
3906 
3907     @Override
setTouchExplorationPassthroughRegion(int displayId, Region region)3908     public void setTouchExplorationPassthroughRegion(int displayId, Region region) {
3909         if (mTraceManager.isA11yTracingEnabled()) {
3910             mTraceManager.logTrace(LOG_TAG + ".setTouchExplorationPassthroughRegion",
3911                     "displayId=" + displayId + ";region=" + region);
3912         }
3913 
3914         mMainHandler.sendMessage(
3915                 obtainMessage(
3916                         AccessibilityManagerService::setTouchExplorationPassthroughRegionInternal,
3917                         this,
3918                         displayId,
3919                         region));
3920     }
3921 
setTouchExplorationPassthroughRegionInternal(int displayId, Region region)3922     private void setTouchExplorationPassthroughRegionInternal(int displayId, Region region) {
3923         synchronized (mLock) {
3924             if (mHasInputFilter && mInputFilter != null) {
3925                 mInputFilter.setTouchExplorationPassthroughRegion(displayId, region);
3926             }
3927         }
3928     }
3929 
setGestureDetectionPassthroughRegionInternal(int displayId, Region region)3930     private void setGestureDetectionPassthroughRegionInternal(int displayId, Region region) {
3931         synchronized (mLock) {
3932             if (mHasInputFilter && mInputFilter != null) {
3933                 mInputFilter.setGestureDetectionPassthroughRegion(displayId, region);
3934             }
3935         }
3936     }
3937 
updateFocusAppearanceDataLocked(AccessibilityUserState userState)3938     private void updateFocusAppearanceDataLocked(AccessibilityUserState userState) {
3939         if (userState.mUserId != mCurrentUserId) {
3940             return;
3941         }
3942 
3943         mMainHandler.post(() -> {
3944             broadcastToClients(userState, ignoreRemoteException(client -> {
3945                 client.mCallback.setFocusAppearance(userState.getFocusStrokeWidthLocked(),
3946                         userState.getFocusColorLocked());
3947             }));
3948         });
3949 
3950     }
3951 
getTraceManager()3952     AccessibilityTraceManager getTraceManager() {
3953         return mTraceManager;
3954     }
3955 }
3956