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.Manifest.permission.CREATE_VIRTUAL_DEVICE;
20 import static android.Manifest.permission.INJECT_EVENTS;
21 import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
22 import static android.Manifest.permission.MANAGE_ACCESSIBILITY;
23 import static android.Manifest.permission.MANAGE_BIND_INSTANT_SERVICE;
24 import static android.Manifest.permission.MODIFY_ACCESSIBILITY_DATA;
25 import static android.Manifest.permission.RETRIEVE_WINDOW_CONTENT;
26 import static android.Manifest.permission.SET_SYSTEM_AUDIO_CAPTION;
27 import static android.Manifest.permission.STATUS_BAR_SERVICE;
28 import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON;
29 import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_MANAGER;
30 import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_MANAGER_CLIENT;
31 import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE_CLIENT;
32 import static android.accessibilityservice.AccessibilityTrace.FLAGS_FINGERPRINT;
33 import static android.accessibilityservice.AccessibilityTrace.FLAGS_INPUT_FILTER;
34 import static android.accessibilityservice.AccessibilityTrace.FLAGS_MAGNIFICATION_CONNECTION;
35 import static android.accessibilityservice.AccessibilityTrace.FLAGS_PACKAGE_BROADCAST_RECEIVER;
36 import static android.accessibilityservice.AccessibilityTrace.FLAGS_USER_BROADCAST_RECEIVER;
37 import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL;
38 import static android.companion.virtual.VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED;
39 import static android.companion.virtual.VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID;
40 import static android.content.Context.DEVICE_ID_DEFAULT;
41 import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED;
42 import static android.view.accessibility.AccessibilityManager.FlashNotificationReason;
43 
44 import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME;
45 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
46 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
47 import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
48 import static com.android.internal.accessibility.common.ShortcutConstants.USER_SHORTCUT_TYPES;
49 import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
50 import static com.android.internal.accessibility.util.AccessibilityStatsLogUtils.logAccessibilityShortcutActivated;
51 import static com.android.internal.util.FunctionalUtils.ignoreRemoteException;
52 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
53 import static com.android.server.accessibility.AccessibilityUserState.doesShortcutTargetsStringContain;
54 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
55 
56 import android.accessibilityservice.AccessibilityGestureEvent;
57 import android.accessibilityservice.AccessibilityService;
58 import android.accessibilityservice.AccessibilityServiceInfo;
59 import android.accessibilityservice.AccessibilityShortcutInfo;
60 import android.accessibilityservice.IAccessibilityServiceClient;
61 import android.accessibilityservice.MagnificationConfig;
62 import android.accessibilityservice.TouchInteractionController;
63 import android.annotation.EnforcePermission;
64 import android.annotation.NonNull;
65 import android.annotation.Nullable;
66 import android.annotation.PermissionManuallyEnforced;
67 import android.annotation.RequiresNoPermission;
68 import android.annotation.SuppressLint;
69 import android.annotation.UserIdInt;
70 import android.app.ActivityOptions;
71 import android.app.AlertDialog;
72 import android.app.AppOpsManager;
73 import android.app.PendingIntent;
74 import android.app.RemoteAction;
75 import android.app.admin.DevicePolicyManager;
76 import android.app.ecm.EnhancedConfirmationManager;
77 import android.appwidget.AppWidgetManagerInternal;
78 import android.content.ActivityNotFoundException;
79 import android.content.BroadcastReceiver;
80 import android.content.ComponentName;
81 import android.content.ContentResolver;
82 import android.content.Context;
83 import android.content.DialogInterface;
84 import android.content.DialogInterface.OnClickListener;
85 import android.content.Intent;
86 import android.content.IntentFilter;
87 import android.content.pm.PackageManager;
88 import android.content.pm.PackageManagerInternal;
89 import android.content.pm.ParceledListSlice;
90 import android.content.pm.ResolveInfo;
91 import android.content.pm.ServiceInfo;
92 import android.database.ContentObserver;
93 import android.graphics.Matrix;
94 import android.graphics.Point;
95 import android.graphics.Rect;
96 import android.graphics.Region;
97 import android.hardware.display.DisplayManager;
98 import android.hardware.fingerprint.IFingerprintService;
99 import android.media.AudioManagerInternal;
100 import android.net.Uri;
101 import android.os.Binder;
102 import android.os.Build;
103 import android.os.Bundle;
104 import android.os.Handler;
105 import android.os.IBinder;
106 import android.os.Looper;
107 import android.os.Message;
108 import android.os.PermissionEnforcer;
109 import android.os.PowerManager;
110 import android.os.Process;
111 import android.os.RemoteCallbackList;
112 import android.os.RemoteException;
113 import android.os.ResultReceiver;
114 import android.os.ServiceManager;
115 import android.os.ShellCallback;
116 import android.os.SystemClock;
117 import android.os.UserHandle;
118 import android.os.UserManager;
119 import android.provider.Settings;
120 import android.provider.SettingsStringUtil.SettingStringHelper;
121 import android.safetycenter.SafetyCenterManager;
122 import android.text.TextUtils;
123 import android.text.TextUtils.SimpleStringSplitter;
124 import android.util.ArrayMap;
125 import android.util.ArraySet;
126 import android.util.IntArray;
127 import android.util.Log;
128 import android.util.Pair;
129 import android.util.Slog;
130 import android.util.SparseArray;
131 import android.util.SparseBooleanArray;
132 import android.view.Display;
133 import android.view.IWindow;
134 import android.view.InputDevice;
135 import android.view.InputEvent;
136 import android.view.KeyEvent;
137 import android.view.MagnificationSpec;
138 import android.view.MotionEvent;
139 import android.view.SurfaceControl;
140 import android.view.WindowInfo;
141 import android.view.WindowManager;
142 import android.view.accessibility.AccessibilityEvent;
143 import android.view.accessibility.AccessibilityInteractionClient;
144 import android.view.accessibility.AccessibilityManager;
145 import android.view.accessibility.AccessibilityNodeInfo;
146 import android.view.accessibility.AccessibilityWindowAttributes;
147 import android.view.accessibility.AccessibilityWindowInfo;
148 import android.view.accessibility.IAccessibilityInteractionConnection;
149 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
150 import android.view.accessibility.IAccessibilityManager;
151 import android.view.accessibility.IAccessibilityManagerClient;
152 import android.view.accessibility.IMagnificationConnection;
153 import android.view.inputmethod.EditorInfo;
154 
155 import com.android.internal.R;
156 import com.android.internal.accessibility.AccessibilityShortcutController;
157 import com.android.internal.accessibility.AccessibilityShortcutController.FrameworkFeatureInfo;
158 import com.android.internal.accessibility.AccessibilityShortcutController.LaunchableFrameworkFeatureInfo;
159 import com.android.internal.accessibility.common.ShortcutConstants;
160 import com.android.internal.accessibility.common.ShortcutConstants.FloatingMenuSize;
161 import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity;
162 import com.android.internal.accessibility.dialog.AccessibilityShortcutChooserActivity;
163 import com.android.internal.accessibility.util.AccessibilityUtils;
164 import com.android.internal.accessibility.util.ShortcutUtils;
165 import com.android.internal.annotations.GuardedBy;
166 import com.android.internal.annotations.VisibleForTesting;
167 import com.android.internal.content.PackageMonitor;
168 import com.android.internal.inputmethod.IAccessibilityInputMethodSession;
169 import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
170 import com.android.internal.os.BackgroundThread;
171 import com.android.internal.util.ArrayUtils;
172 import com.android.internal.util.DumpUtils;
173 import com.android.internal.util.IntPair;
174 import com.android.internal.util.Preconditions;
175 import com.android.modules.expresslog.Counter;
176 import com.android.server.AccessibilityManagerInternal;
177 import com.android.server.LocalServices;
178 import com.android.server.SystemService;
179 import com.android.server.accessibility.magnification.MagnificationConnectionManager;
180 import com.android.server.accessibility.magnification.MagnificationController;
181 import com.android.server.accessibility.magnification.MagnificationProcessor;
182 import com.android.server.accessibility.magnification.MagnificationScaleProvider;
183 import com.android.server.inputmethod.InputMethodManagerInternal;
184 import com.android.server.pm.UserManagerInternal;
185 import com.android.server.policy.WindowManagerPolicy;
186 import com.android.server.statusbar.StatusBarManagerInternal;
187 import com.android.server.utils.Slogf;
188 import com.android.server.wm.ActivityTaskManagerInternal;
189 import com.android.server.wm.WindowManagerInternal;
190 import com.android.settingslib.RestrictedLockUtils;
191 
192 import org.xmlpull.v1.XmlPullParserException;
193 
194 import java.io.FileDescriptor;
195 import java.io.IOException;
196 import java.io.PrintWriter;
197 import java.util.ArrayList;
198 import java.util.Arrays;
199 import java.util.Collections;
200 import java.util.HashSet;
201 import java.util.Iterator;
202 import java.util.List;
203 import java.util.Map;
204 import java.util.Objects;
205 import java.util.Set;
206 import java.util.concurrent.Executors;
207 import java.util.function.Consumer;
208 import java.util.function.Function;
209 import java.util.function.Predicate;
210 import java.util.stream.Collectors;
211 
212 /**
213  * This class is instantiated by the system as a system level service and can be
214  * accessed only by the system. The task of this service is to be a centralized
215  * event dispatch for {@link AccessibilityEvent}s generated across all processes
216  * on the device. Events are dispatched to {@link AccessibilityService}s.
217  */
218 public class AccessibilityManagerService extends IAccessibilityManager.Stub
219         implements AbstractAccessibilityServiceConnection.SystemSupport,
220         AccessibilityUserState.ServiceInfoChangeListener,
221         AccessibilityWindowManager.AccessibilityEventSender,
222         AccessibilitySecurityPolicy.AccessibilityUserManager,
223         SystemActionPerformer.SystemActionsChangedListener,
224         SystemActionPerformer.DisplayUpdateCallBack, ProxyManager.SystemSupport {
225 
226     private static final boolean DEBUG = false;
227 
228     private static final String LOG_TAG = "AccessibilityManagerService";
229 
230     // TODO: This is arbitrary. When there is time implement this by watching
231     //       when that accessibility services are bound.
232     private static final int WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS = 3000;
233 
234     // TODO: Restructure service initialization so services aren't connected before all of
235     //       their capabilities are ready.
236     private static final int WAIT_INPUT_FILTER_INSTALL_TIMEOUT_MS = 1000;
237 
238 
239     // This postpones state changes events when a window doesn't exist with the expectation that
240     // a race condition will resolve. It is determined by observing elapsed time of the
241     // corresponding window added.
242     //TODO(b/230810909) : Fix it with a better idea.
243     private static final int POSTPONE_WINDOW_STATE_CHANGED_EVENT_TIMEOUT_MILLIS = 500;
244 
245     private static final String FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE =
246         "registerUiTestAutomationService";
247 
248     private static final String GET_WINDOW_TOKEN = "getWindowToken";
249 
250     private static final String SET_PIP_ACTION_REPLACEMENT =
251             "setPictureInPictureActionReplacingConnection";
252 
253     /**
254      * An intent action to launch Hearing devices dialog.
255      */
256     @VisibleForTesting
257     static final String ACTION_LAUNCH_HEARING_DEVICES_DIALOG =
258             "com.android.systemui.action.LAUNCH_HEARING_DEVICES_DIALOG";
259 
260     private static final char COMPONENT_NAME_SEPARATOR = ':';
261 
262     private static final int OWN_PROCESS_ID = android.os.Process.myPid();
263 
264     public static final int INVALID_SERVICE_ID = -1;
265 
266     // Each service has an ID. Also provide one for magnification gesture handling
267     public static final int MAGNIFICATION_GESTURE_HANDLER_ID = 0;
268 
269     private static int sIdCounter = MAGNIFICATION_GESTURE_HANDLER_ID + 1;
270     /**
271      * The counter metric id tracking how many times users add qs shortcut for a11y features.
272      *
273      * <p>Defined in frameworks/proto_logging/stats/express/catalog/accessibility.cfg.
274      */
275     static final String METRIC_ID_QS_SHORTCUT_ADD = "accessibility.value_qs_shortcut_add";
276 
277     /**
278      * The counter metric id tracking how many times users remove qs shortcut for a11y features.
279      *
280      * <p>Defined in frameworks/proto_logging/stats/express/catalog/accessibility.cfg.
281      */
282     static final String METRIC_ID_QS_SHORTCUT_REMOVE = "accessibility.value_qs_shortcut_remove";
283 
284 
285     private final Context mContext;
286 
287     private final Object mLock = new Object();
288 
289     private final SimpleStringSplitter mStringColonSplitter =
290             new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
291 
292     private final Rect mTempRect = new Rect();
293     private final Rect mTempRect1 = new Rect();
294 
295     private final PackageManager mPackageManager;
296 
297     private final PowerManager mPowerManager;
298 
299     private final WindowManagerInternal mWindowManagerService;
300 
301     private final AccessibilitySecurityPolicy mSecurityPolicy;
302 
303     private final AccessibilityWindowManager mA11yWindowManager;
304 
305     private final AccessibilityDisplayListener mA11yDisplayListener;
306 
307     private final ActivityTaskManagerInternal mActivityTaskManagerService;
308 
309     private final MagnificationController mMagnificationController;
310     private final MagnificationProcessor mMagnificationProcessor;
311 
312     private final Handler mMainHandler;
313 
314     // Lazily initialized - access through getSystemActionPerformer()
315     private SystemActionPerformer mSystemActionPerformer;
316 
317     private InteractionBridge mInteractionBridge;
318 
319     private AlertDialog mEnableTouchExplorationDialog;
320 
321     private AccessibilityInputFilter mInputFilter;
322 
323     private boolean mHasInputFilter;
324 
325     private boolean mInputFilterInstalled;
326 
327     private KeyEventDispatcher mKeyEventDispatcher;
328 
329     private SparseArray<MotionEventInjector> mMotionEventInjectors;
330 
331     private FingerprintGestureDispatcher mFingerprintGestureDispatcher;
332 
333     private final Set<ComponentName> mTempComponentNameSet = new HashSet<>();
334 
335     private final IntArray mTempIntArray = new IntArray(0);
336 
337     private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients =
338             new RemoteCallbackList<>();
339 
340     private PackageMonitor mPackageMonitor;
341 
342     @VisibleForTesting
343     final SparseArray<AccessibilityUserState> mUserStates = new SparseArray<>();
344 
345     private final UiAutomationManager mUiAutomationManager = new UiAutomationManager(mLock);
346     private final ProxyManager mProxyManager;
347     private final AccessibilityTraceManager mTraceManager;
348     private final CaptioningManagerImpl mCaptioningManagerImpl;
349 
350     private final List<SendWindowStateChangedEventRunnable> mSendWindowStateChangedEventRunnables =
351             new ArrayList<>();
352 
353     @GuardedBy("mLock")
354     private @UserIdInt int mCurrentUserId = UserHandle.USER_SYSTEM;
355 
356     // TODO(b/255426725): temporary workaround to support visible background users for UiAutomation:
357     // when the UiAutomation is set in a visible background user, mCurrentUserId points to that user
358     // and mRealCurrentUserId points to the "real" current user; otherwise, mRealCurrentUserId
359     // is set as UserHandle.USER_CURRENT.
360     @GuardedBy("mLock")
361     private @UserIdInt int mRealCurrentUserId = UserHandle.USER_CURRENT;
362 
363     // TODO(b/255426725): temporary workaround to support visible background users for UiAutomation
364     // purposes - in the long term, the whole service should be refactored so it handles "visible"
365     // users, not current user. Notice that because this is temporary, it's not trying to optimize
366     // performance / utilization (for example, it's not using an IntArray)
367     @GuardedBy("mLock")
368     @Nullable // only set when device supports visible background users
369     private final SparseBooleanArray mVisibleBgUserIds;
370 
371     //TODO: Remove this hack
372     private boolean mInitialized;
373 
374     private Point mTempPoint = new Point();
375     private boolean mIsAccessibilityButtonShown;
376     private boolean mInputBound;
377     IRemoteAccessibilityInputConnection mRemoteInputConnection;
378     EditorInfo mEditorInfo;
379     boolean mRestarting;
380     boolean mInputSessionRequested;
381     private SparseArray<SurfaceControl> mA11yOverlayLayers = new SparseArray<>();
382 
383     private final FlashNotificationsController mFlashNotificationsController;
384     private final UserManagerInternal mUmi;
385 
getCurrentUserStateLocked()386     private AccessibilityUserState getCurrentUserStateLocked() {
387         return getUserStateLocked(mCurrentUserId);
388     }
389 
390     /**
391      * Changes the magnification mode on the given display.
392      *
393      * @param displayId the logical display
394      * @param magnificationMode the target magnification mode
395      */
changeMagnificationMode(int displayId, int magnificationMode)396     public void changeMagnificationMode(int displayId, int magnificationMode) {
397         synchronized (mLock) {
398             if (displayId == Display.DEFAULT_DISPLAY) {
399                 persistMagnificationModeSettingsLocked(magnificationMode);
400             } else {
401                 final AccessibilityUserState userState = getCurrentUserStateLocked();
402                 final int currentMode = userState.getMagnificationModeLocked(displayId);
403                 if (magnificationMode != currentMode) {
404                     userState.setMagnificationModeLocked(displayId, magnificationMode);
405                     updateMagnificationModeChangeSettingsLocked(userState, displayId);
406                 }
407             }
408         }
409     }
410 
411     private static final class LocalServiceImpl extends AccessibilityManagerInternal {
412         @NonNull
413         private final AccessibilityManagerService mService;
414 
LocalServiceImpl(@onNull AccessibilityManagerService service)415         LocalServiceImpl(@NonNull AccessibilityManagerService service) {
416             mService = service;
417         }
418 
419         @Override
setImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions, boolean enabled)420         public void setImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions,
421                 boolean enabled) {
422             mService.scheduleSetImeSessionEnabled(sessions, enabled);
423         }
424 
425         @Override
unbindInput()426         public void unbindInput() {
427             mService.scheduleUnbindInput();
428         }
429 
430         @Override
bindInput()431         public void bindInput() {
432             mService.scheduleBindInput();
433         }
434 
435         @Override
createImeSession(ArraySet<Integer> ignoreSet)436         public void createImeSession(ArraySet<Integer> ignoreSet) {
437             mService.scheduleCreateImeSession(ignoreSet);
438         }
439 
440         @Override
startInput( IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, EditorInfo editorInfo, boolean restarting)441         public void startInput(
442                 IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,
443                 EditorInfo editorInfo, boolean restarting) {
444             mService.scheduleStartInput(remoteAccessibilityInputConnection, editorInfo, restarting);
445         }
446 
447         @Override
performSystemAction(int actionId)448         public void performSystemAction(int actionId) {
449             mService.getSystemActionPerformer().performSystemAction(actionId);
450         }
451 
452         @Override
isTouchExplorationEnabled(@serIdInt int userId)453         public boolean isTouchExplorationEnabled(@UserIdInt int userId) {
454             synchronized (mService.mLock) {
455                 return mService.getUserStateLocked(userId).isTouchExplorationEnabledLocked();
456             }
457         }
458     }
459 
460     public static final class Lifecycle extends SystemService {
461         private final AccessibilityManagerService mService;
462 
Lifecycle(Context context)463         public Lifecycle(Context context) {
464             super(context);
465             mService = new AccessibilityManagerService(context);
466         }
467 
468         @Override
onStart()469         public void onStart() {
470             LocalServices.addService(AccessibilityManagerInternal.class,
471                     new LocalServiceImpl(mService));
472             publishBinderService(Context.ACCESSIBILITY_SERVICE, mService);
473         }
474 
475         @Override
onBootPhase(int phase)476         public void onBootPhase(int phase) {
477             mService.onBootPhase(phase);
478         }
479     }
480 
481     @VisibleForTesting
AccessibilityManagerService( Context context, Handler handler, PackageManager packageManager, AccessibilitySecurityPolicy securityPolicy, SystemActionPerformer systemActionPerformer, AccessibilityWindowManager a11yWindowManager, AccessibilityDisplayListener a11yDisplayListener, MagnificationController magnificationController, @Nullable AccessibilityInputFilter inputFilter, ProxyManager proxyManager, PermissionEnforcer permissionEnforcer)482     AccessibilityManagerService(
483             Context context,
484             Handler handler,
485             PackageManager packageManager,
486             AccessibilitySecurityPolicy securityPolicy,
487             SystemActionPerformer systemActionPerformer,
488             AccessibilityWindowManager a11yWindowManager,
489             AccessibilityDisplayListener a11yDisplayListener,
490             MagnificationController magnificationController,
491             @Nullable AccessibilityInputFilter inputFilter,
492             ProxyManager proxyManager,
493             PermissionEnforcer permissionEnforcer) {
494         super(permissionEnforcer);
495         mContext = context;
496         mPowerManager =  (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
497         mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
498         mTraceManager = AccessibilityTraceManager.getInstance(
499                 mWindowManagerService.getAccessibilityController(), this, mLock);
500         mMainHandler = handler;
501         mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
502         mPackageManager = packageManager;
503         mSecurityPolicy = securityPolicy;
504         mSystemActionPerformer = systemActionPerformer;
505         mA11yWindowManager = a11yWindowManager;
506         mA11yDisplayListener = a11yDisplayListener;
507         mMagnificationController = magnificationController;
508         mMagnificationProcessor = new MagnificationProcessor(mMagnificationController);
509         mCaptioningManagerImpl = new CaptioningManagerImpl(mContext);
510         mProxyManager = proxyManager;
511         if (inputFilter != null) {
512             mInputFilter = inputFilter;
513             mHasInputFilter = true;
514         }
515         mFlashNotificationsController = new FlashNotificationsController(mContext);
516         mUmi = LocalServices.getService(UserManagerInternal.class);
517         // TODO(b/255426725): not used on tests
518         mVisibleBgUserIds = null;
519 
520         init();
521     }
522 
523     /**
524      * Creates a new instance.
525      *
526      * @param context A {@link Context} instance.
527      */
AccessibilityManagerService(Context context)528     public AccessibilityManagerService(Context context) {
529         super(PermissionEnforcer.fromContext(context));
530         mContext = context;
531         mPowerManager = context.getSystemService(PowerManager.class);
532         mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
533         mTraceManager = AccessibilityTraceManager.getInstance(
534                 mWindowManagerService.getAccessibilityController(), this, mLock);
535         mMainHandler = new MainHandler(mContext.getMainLooper());
536         mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
537         mPackageManager = mContext.getPackageManager();
538         final PolicyWarningUIController policyWarningUIController = new PolicyWarningUIController(
539                 mMainHandler, context,
540                 new PolicyWarningUIController.NotificationController(context));
541         mSecurityPolicy = new AccessibilitySecurityPolicy(policyWarningUIController, mContext,
542                 this, LocalServices.getService(PackageManagerInternal.class));
543         mA11yWindowManager = new AccessibilityWindowManager(mLock, mMainHandler,
544                 mWindowManagerService, this, mSecurityPolicy, this, mTraceManager);
545         mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler);
546         mMagnificationController = new MagnificationController(
547                 this,
548                 mLock,
549                 mContext,
550                 new MagnificationScaleProvider(mContext),
551                 Executors.newSingleThreadExecutor()
552         );
553         mMagnificationProcessor = new MagnificationProcessor(mMagnificationController);
554         mCaptioningManagerImpl = new CaptioningManagerImpl(mContext);
555         mProxyManager = new ProxyManager(mLock, mA11yWindowManager, mContext, mMainHandler,
556                 mUiAutomationManager, this);
557         mFlashNotificationsController = new FlashNotificationsController(mContext);
558         mUmi = LocalServices.getService(UserManagerInternal.class);
559 
560         if (UserManager.isVisibleBackgroundUsersEnabled()) {
561             mVisibleBgUserIds = new SparseBooleanArray();
562             mUmi.addUserVisibilityListener((u, v) -> onUserVisibilityChanged(u, v));
563         } else {
564             mVisibleBgUserIds = null;
565         }
566 
567         init();
568     }
569 
init()570     private void init() {
571         mSecurityPolicy.setAccessibilityWindowManager(mA11yWindowManager);
572         registerBroadcastReceivers();
573         new AccessibilityContentObserver(mMainHandler).register(
574                 mContext.getContentResolver());
575         disableAccessibilityMenuToMigrateIfNeeded();
576     }
577 
578     /**
579      * Returns if the current thread is holding {@link #mLock}. Used for testing
580      * deadlock bug fixes.
581      *
582      * <p><strong>Warning:</strong> this should not be used for production logic
583      * because by the time you receive an answer it may no longer be valid.
584      * </p>
585      */
586     @VisibleForTesting
unsafeIsLockHeld()587     boolean unsafeIsLockHeld() {
588         return Thread.holdsLock(mLock);
589     }
590 
591     /**
592      * Returns if the service is initialized.
593      *
594      * The service is considered initialized when the user switch happened.
595      */
isServiceInitializedLocked()596     private boolean isServiceInitializedLocked() {
597         return mInitialized;
598     }
599 
600     @Override
getCurrentUserIdLocked()601     public int getCurrentUserIdLocked() {
602         return mCurrentUserId;
603     }
604 
605     @GuardedBy("mLock")
606     @Override
getVisibleUserIdsLocked()607     public SparseBooleanArray getVisibleUserIdsLocked() {
608         return mVisibleBgUserIds;
609     }
610 
611     @Override
isAccessibilityButtonShown()612     public boolean isAccessibilityButtonShown() {
613         return mIsAccessibilityButtonShown;
614     }
615 
616     @Override
getWindowTransformationMatrixAndMagnificationSpec( int windowId)617     public Pair<float[], MagnificationSpec> getWindowTransformationMatrixAndMagnificationSpec(
618             int windowId) {
619         WindowInfo windowInfo;
620         synchronized (mLock) {
621             windowInfo = mA11yWindowManager.findWindowInfoByIdLocked(windowId);
622         }
623         if (windowInfo != null) {
624             final MagnificationSpec spec = new MagnificationSpec();
625             spec.setTo(windowInfo.mMagnificationSpec);
626             return new Pair<>(windowInfo.mTransformMatrix, spec);
627         } else {
628             // If the framework doesn't track windows, we fall back to get the pair of
629             // transformation matrix and MagnificationSpe from the WindowManagerService's
630             // WindowState.
631             IBinder token;
632             synchronized (mLock) {
633                 token = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(mCurrentUserId,
634                         windowId);
635             }
636             Pair<Matrix, MagnificationSpec> pair =
637                     mWindowManagerService.getWindowTransformationMatrixAndMagnificationSpec(token);
638             final float[] outTransformationMatrix = new float[9];
639             final Matrix tmpMatrix = pair.first;
640             final MagnificationSpec spec = pair.second;
641             if (!spec.isNop()) {
642                 tmpMatrix.postScale(spec.scale, spec.scale);
643                 tmpMatrix.postTranslate(spec.offsetX, spec.offsetY);
644             }
645             tmpMatrix.getValues(outTransformationMatrix);
646 
647             return new Pair<>(outTransformationMatrix, pair.second);
648         }
649     }
650 
651     @Override
652     @RequiresNoPermission
getWindowTransformationSpec( int windowId)653     public IAccessibilityManager.WindowTransformationSpec getWindowTransformationSpec(
654             int windowId) {
655         IAccessibilityManager.WindowTransformationSpec windowTransformationSpec =
656                 new IAccessibilityManager.WindowTransformationSpec();
657         Pair<float[], MagnificationSpec> result =
658                 getWindowTransformationMatrixAndMagnificationSpec(windowId);
659         windowTransformationSpec.transformationMatrix = result.first;
660         windowTransformationSpec.magnificationSpec = result.second;
661         return windowTransformationSpec;
662     }
663 
664     @Override
onServiceInfoChangedLocked(AccessibilityUserState userState)665     public void onServiceInfoChangedLocked(AccessibilityUserState userState) {
666         mSecurityPolicy.onBoundServicesChangedLocked(userState.mUserId,
667                 userState.mBoundServices);
668         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
669     }
670 
671     @Nullable
getFingerprintGestureDispatcher()672     public FingerprintGestureDispatcher getFingerprintGestureDispatcher() {
673         return mFingerprintGestureDispatcher;
674     }
675 
676     /**
677      * Called by the {@link AccessibilityInputFilter} when the filter install state changes.
678      */
onInputFilterInstalled(boolean installed)679     public void onInputFilterInstalled(boolean installed) {
680         synchronized (mLock) {
681             mInputFilterInstalled = installed;
682             mLock.notifyAll();
683         }
684     }
685 
onBootPhase(int phase)686     private void onBootPhase(int phase) {
687         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
688             if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
689                 mSecurityPolicy.setAppWidgetManager(
690                         LocalServices.getService(AppWidgetManagerInternal.class));
691             }
692         }
693 
694         // SafetyCenterService is ready after this phase.
695         if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
696             setNonA11yToolNotificationToMatchSafetyCenter();
697         }
698     }
699 
setNonA11yToolNotificationToMatchSafetyCenter()700     private void setNonA11yToolNotificationToMatchSafetyCenter() {
701         final boolean sendNotification = !mContext.getSystemService(
702                 SafetyCenterManager.class).isSafetyCenterEnabled();
703         synchronized (mLock) {
704             mSecurityPolicy.setSendingNonA11yToolNotificationLocked(sendNotification);
705         }
706     }
707 
708     /**
709      * Returns the lock object for any synchronized test blocks.
710      * External classes should only use for testing.
711      * @return lock object.
712      */
713     @VisibleForTesting
getLock()714     Object getLock() {
715         return mLock;
716     }
717 
getCurrentUserState()718     AccessibilityUserState getCurrentUserState() {
719         synchronized (mLock) {
720             return getCurrentUserStateLocked();
721         }
722     }
723 
getUserState(int userId)724     private AccessibilityUserState getUserState(int userId) {
725         synchronized (mLock) {
726             return getUserStateLocked(userId);
727         }
728     }
729 
730     @NonNull
getUserStateLocked(int userId)731     private AccessibilityUserState getUserStateLocked(int userId) {
732         AccessibilityUserState state = mUserStates.get(userId);
733         if (state == null) {
734             state = new AccessibilityUserState(userId, mContext, this);
735             mUserStates.put(userId, state);
736         }
737         return state;
738     }
739 
getBindInstantServiceAllowed(int userId)740     boolean getBindInstantServiceAllowed(int userId) {
741         synchronized (mLock) {
742             final AccessibilityUserState userState = getUserStateLocked(userId);
743             return userState.getBindInstantServiceAllowedLocked();
744         }
745     }
746 
setBindInstantServiceAllowed(int userId, boolean allowed)747     void setBindInstantServiceAllowed(int userId, boolean allowed) {
748         mContext.enforceCallingOrSelfPermission(
749                 MANAGE_BIND_INSTANT_SERVICE, "setBindInstantServiceAllowed");
750         synchronized (mLock) {
751             final AccessibilityUserState userState = getUserStateLocked(userId);
752             if (allowed != userState.getBindInstantServiceAllowedLocked()) {
753                 userState.setBindInstantServiceAllowedLocked(allowed);
754                 onUserStateChangedLocked(userState);
755             }
756         }
757     }
758 
onSomePackagesChangedLocked( @ullable List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos, @Nullable List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos)759     private void onSomePackagesChangedLocked(
760             @Nullable List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos,
761             @Nullable List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos) {
762         final AccessibilityUserState userState = getCurrentUserStateLocked();
763         // Reload the installed services since some services may have different attributes
764         // or resolve info (does not support equals), etc. Remove them then to force reload.
765         userState.mInstalledServices.clear();
766         if (readConfigurationForUserStateLocked(userState,
767                     parsedAccessibilityServiceInfos, parsedAccessibilityShortcutInfos)) {
768             onUserStateChangedLocked(userState);
769         }
770     }
771 
onPackageRemovedLocked(String packageName)772     private void onPackageRemovedLocked(String packageName) {
773         final AccessibilityUserState userState = getCurrentUserState();
774         final Predicate<ComponentName> filter =
775                 component -> component != null && component.getPackageName().equals(
776                         packageName);
777         userState.mBindingServices.removeIf(filter);
778         userState.mCrashedServices.removeIf(filter);
779         final Iterator<ComponentName> it = userState.mEnabledServices.iterator();
780         boolean anyServiceRemoved = false;
781         while (it.hasNext()) {
782             final ComponentName comp = it.next();
783             final String compPkg = comp.getPackageName();
784             if (compPkg.equals(packageName)) {
785                 it.remove();
786                 userState.mTouchExplorationGrantedServices.remove(comp);
787                 anyServiceRemoved = true;
788             }
789         }
790         if (anyServiceRemoved) {
791             // Update the enabled services setting.
792             persistComponentNamesToSettingLocked(
793                     Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
794                     userState.mEnabledServices, mCurrentUserId);
795             // Update the touch exploration granted services setting.
796             persistComponentNamesToSettingLocked(
797                     Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
798                     userState.mTouchExplorationGrantedServices, mCurrentUserId);
799             onUserStateChangedLocked(userState);
800         }
801     }
802 
803     /**
804      * Handles a package or packages being force stopped.
805      * Will disable any relevant services,
806      * and remove any button targets of continuous services,
807      * denoted by {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON}.
808      * If the result is {@code true},
809      * then {@link AccessibilityManagerService#onUserStateChangedLocked(
810      * AccessibilityUserState, boolean)} should be called afterwards.
811      *
812      * @param packages list of packages that have stopped.
813      * @param userState user state to be read & modified.
814      * @return {@code true} if the lists of enabled services or buttons were changed,
815      * {@code false} otherwise.
816      */
817     @VisibleForTesting
onPackagesForceStoppedLocked( String[] packages, AccessibilityUserState userState)818     boolean onPackagesForceStoppedLocked(
819             String[] packages, AccessibilityUserState userState) {
820         final List<String> continuousServicePackages =
821                 userState.mInstalledServices.stream().filter(service ->
822                         (service.flags & FLAG_REQUEST_ACCESSIBILITY_BUTTON)
823                                 == FLAG_REQUEST_ACCESSIBILITY_BUTTON
824                 ).map(service -> service.getComponentName().flattenToString()).toList();
825 
826         boolean enabledServicesChanged = false;
827         final Iterator<ComponentName> it = userState.mEnabledServices.iterator();
828         while (it.hasNext()) {
829             final ComponentName comp = it.next();
830             final String compPkg = comp.getPackageName();
831             for (String pkg : packages) {
832                 if (compPkg.equals(pkg)) {
833                     it.remove();
834                     userState.getBindingServicesLocked().remove(comp);
835                     userState.getCrashedServicesLocked().remove(comp);
836                     enabledServicesChanged = true;
837                     break;
838                 }
839             }
840         }
841         if (enabledServicesChanged) {
842             persistComponentNamesToSettingLocked(
843                     Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
844                     userState.mEnabledServices, userState.mUserId);
845         }
846 
847         boolean buttonTargetsChanged = userState.mAccessibilityButtonTargets.removeIf(
848                 target -> continuousServicePackages.stream().anyMatch(
849                         pkg -> Objects.equals(target, pkg)));
850         if (buttonTargetsChanged) {
851             persistColonDelimitedSetToSettingLocked(
852                     Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
853                     userState.mUserId,
854                     userState.mAccessibilityButtonTargets, str -> str);
855         }
856 
857         return enabledServicesChanged || buttonTargetsChanged;
858     }
859 
860     @VisibleForTesting
getPackageMonitor()861     PackageMonitor getPackageMonitor() {
862         return mPackageMonitor;
863     }
864 
865     @VisibleForTesting
setPackageMonitor(PackageMonitor monitor)866     void setPackageMonitor(PackageMonitor monitor) {
867         mPackageMonitor = monitor;
868     }
869 
870     @SuppressLint("MissingPermission")
registerBroadcastReceivers()871     private void registerBroadcastReceivers() {
872         // package changes
873         mPackageMonitor = new ManagerPackageMonitor(this);
874         mPackageMonitor.register(mContext, null,  UserHandle.ALL, true);
875 
876         // user change and unlock
877         IntentFilter intentFilter = new IntentFilter();
878         intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
879         intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
880         intentFilter.addAction(Intent.ACTION_USER_REMOVED);
881         intentFilter.addAction(Intent.ACTION_SETTING_RESTORED);
882 
883         Handler receiverHandler =
884                 Flags.managerAvoidReceiverTimeout() ? BackgroundThread.getHandler() : null;
885         mContext.registerReceiverAsUser(new BroadcastReceiver() {
886             @Override
887             public void onReceive(Context context, Intent intent) {
888                 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_USER_BROADCAST_RECEIVER)) {
889                     mTraceManager.logTrace(
890                             LOG_TAG + ".BR.onReceive",
891                             FLAGS_USER_BROADCAST_RECEIVER,
892                             "context=" + context + ";intent=" + intent);
893                 }
894 
895                 String action = intent.getAction();
896                 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
897                     switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
898                 } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
899                     unlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
900                 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
901                     removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
902                 } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) {
903                     final String which = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
904                     if (which == null) {
905                         return;
906                     }
907                     final String previousValue =
908                             intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE);
909                     final String newValue =
910                             intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
911                     final int restoredFromSdk =
912                             intent.getIntExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
913                     switch (which) {
914                         case Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES -> {
915                             synchronized (mLock) {
916                                 restoreEnabledAccessibilityServicesLocked(
917                                         previousValue, newValue, restoredFromSdk);
918                             }
919                         }
920                         case ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED -> {
921                             synchronized (mLock) {
922                                 restoreLegacyDisplayMagnificationNavBarIfNeededLocked(
923                                         newValue, restoredFromSdk);
924                             }
925                         }
926                         case Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS -> {
927                             synchronized (mLock) {
928                                 restoreAccessibilityButtonTargetsLocked(
929                                         previousValue, newValue);
930                             }
931                         }
932                         case Settings.Secure.ACCESSIBILITY_QS_TARGETS -> {
933                             if (!android.view.accessibility.Flags.a11yQsShortcut()) {
934                                 return;
935                             }
936                             restoreAccessibilityQsTargets(newValue);
937                         }
938                         case Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE -> {
939                             if (!android.view.accessibility.Flags
940                                     .restoreA11yShortcutTargetService()) {
941                                 return;
942                             }
943                             restoreAccessibilityShortcutTargetService(previousValue, newValue);
944                         }
945                     }
946                 }
947             }
948         }, UserHandle.ALL, intentFilter, null, receiverHandler);
949 
950         final IntentFilter filter = new IntentFilter();
951         filter.addAction(SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED);
952         final BroadcastReceiver receiver = new BroadcastReceiver() {
953             @Override
954             public void onReceive(Context context, Intent intent) {
955                 setNonA11yToolNotificationToMatchSafetyCenter();
956             }
957         };
958         mContext.registerReceiverAsUser(
959                 receiver, UserHandle.ALL, filter, null, mMainHandler,
960                 Context.RECEIVER_EXPORTED);
961 
962         if (!android.companion.virtual.flags.Flags.vdmPublicApis()) {
963             final BroadcastReceiver virtualDeviceReceiver = new BroadcastReceiver() {
964                 @Override
965                 public void onReceive(Context context, Intent intent) {
966                     final int deviceId = intent.getIntExtra(
967                             EXTRA_VIRTUAL_DEVICE_ID, DEVICE_ID_DEFAULT);
968                     mProxyManager.clearConnections(deviceId);
969                 }
970             };
971 
972             final IntentFilter virtualDeviceFilter = new IntentFilter(
973                     ACTION_VIRTUAL_DEVICE_REMOVED);
974             mContext.registerReceiver(virtualDeviceReceiver, virtualDeviceFilter,
975                     Context.RECEIVER_NOT_EXPORTED);
976         }
977     }
978 
979     /**
980      * Disables the component returned by
981      * {@link AccessibilityUtils#getAccessibilityMenuComponentToMigrate} so that it does not appear
982      * in Settings or other places that query for installed accessibility services.
983      *
984      * <p>
985      * SettingsProvider is responsible for migrating users off of Menu-outside-system,
986      * which it performs in its initialization before AccessibilityManagerService is started.
987      * </p>
988      */
disableAccessibilityMenuToMigrateIfNeeded()989     private void disableAccessibilityMenuToMigrateIfNeeded() {
990         int userId;
991         synchronized (mLock) {
992             userId = mCurrentUserId;
993         }
994         final ComponentName menuToMigrate =
995                 AccessibilityUtils.getAccessibilityMenuComponentToMigrate(mPackageManager, userId);
996         if (menuToMigrate != null) {
997             // PackageManager#setComponentEnabledSetting disables the component for only the user
998             // linked to PackageManager's context, but mPackageManager is linked to the system user,
999             // so grab a new PackageManager for the current user to support secondary users.
1000             final PackageManager userPackageManager =
1001                     mContext.createContextAsUser(UserHandle.of(userId), /* flags = */ 0)
1002                             .getPackageManager();
1003             userPackageManager.setComponentEnabledSetting(
1004                     menuToMigrate,
1005                     PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
1006                     PackageManager.DONT_KILL_APP);
1007         }
1008     }
1009 
1010     // Called only during settings restore; currently supports only the owner user
1011     // TODO: b/22388012
restoreLegacyDisplayMagnificationNavBarIfNeededLocked(String newSetting, int restoreFromSdkInt)1012     private void restoreLegacyDisplayMagnificationNavBarIfNeededLocked(String newSetting,
1013             int restoreFromSdkInt) {
1014         if (restoreFromSdkInt >= Build.VERSION_CODES.R) {
1015             return;
1016         }
1017 
1018         boolean displayMagnificationNavBarEnabled;
1019         try {
1020             displayMagnificationNavBarEnabled = Integer.parseInt(newSetting) == 1;
1021         } catch (NumberFormatException e) {
1022             Slog.w(LOG_TAG, "number format is incorrect" + e);
1023             return;
1024         }
1025 
1026         final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM);
1027         final Set<String> targetsFromSetting = new ArraySet<>();
1028         readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
1029                 userState.mUserId, str -> str, targetsFromSetting);
1030         final boolean targetsContainMagnification = targetsFromSetting.contains(
1031                 MAGNIFICATION_CONTROLLER_NAME);
1032         if (targetsContainMagnification == displayMagnificationNavBarEnabled) {
1033             return;
1034         }
1035 
1036         if (displayMagnificationNavBarEnabled) {
1037             targetsFromSetting.add(MAGNIFICATION_CONTROLLER_NAME);
1038         } else {
1039             targetsFromSetting.remove(MAGNIFICATION_CONTROLLER_NAME);
1040         }
1041         persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
1042                 userState.mUserId, targetsFromSetting, str -> str);
1043         readAccessibilityButtonTargetsLocked(userState);
1044         onUserStateChangedLocked(userState);
1045     }
1046 
1047     @Override
1048     @RequiresNoPermission
addClient(IAccessibilityManagerClient callback, int userId)1049     public long addClient(IAccessibilityManagerClient callback, int userId) {
1050         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
1051             mTraceManager.logTrace(LOG_TAG + ".addClient", FLAGS_ACCESSIBILITY_MANAGER,
1052                     "callback=" + callback + ";userId=" + userId);
1053         }
1054 
1055         synchronized (mLock) {
1056             // We treat calls from a profile as if made by its parent as profiles
1057             // share the accessibility state of the parent. The call below
1058             // performs the current profile parent resolution.
1059             final int resolvedUserId = mSecurityPolicy
1060                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
1061 
1062             AccessibilityUserState userState = getUserStateLocked(resolvedUserId);
1063             // Support a process moving from the default device to a single virtual
1064             // device.
1065             final int deviceId = mProxyManager.getFirstDeviceIdForUidLocked(
1066                     Binder.getCallingUid());
1067             Client client = new Client(callback, Binder.getCallingUid(), userState, deviceId);
1068             // If the client is from a process that runs across users such as
1069             // the system UI or the system we add it to the global state that
1070             // is shared across users.
1071             if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
1072                 if (mProxyManager.isProxyedDeviceId(deviceId)) {
1073                     if (DEBUG) {
1074                         Slog.v(LOG_TAG, "Added global client for proxy-ed pid: "
1075                                 + Binder.getCallingPid() + " for device id " + deviceId
1076                                 + " with package names " + Arrays.toString(client.mPackageNames));
1077                     }
1078                     return IntPair.of(mProxyManager.getStateLocked(deviceId),
1079                             client.mLastSentRelevantEventTypes);
1080                 }
1081                 mGlobalClients.register(callback, client);
1082                 if (DEBUG) {
1083                     Slog.i(LOG_TAG, "Added global client for pid:" + Binder.getCallingPid());
1084                 }
1085             } else {
1086                 // If the display belongs to a proxy connections
1087                 if (mProxyManager.isProxyedDeviceId(deviceId)) {
1088                     if (DEBUG) {
1089                         Slog.v(LOG_TAG, "Added user client for proxy-ed pid: "
1090                                 + Binder.getCallingPid() + " for device id " + deviceId
1091                                 + " with package names " + Arrays.toString(client.mPackageNames));
1092                     }
1093                     return IntPair.of(mProxyManager.getStateLocked(deviceId),
1094                             client.mLastSentRelevantEventTypes);
1095                 }
1096                 userState.mUserClients.register(callback, client);
1097                 // If this client is not for the current user we do not
1098                 // return a state since it is not for the foreground user.
1099                 // We will send the state to the client on a user switch.
1100                 if (DEBUG) {
1101                     Slog.i(LOG_TAG, "Added user client for pid:" + Binder.getCallingPid()
1102                             + " and userId:" + mCurrentUserId);
1103                 }
1104             }
1105             return IntPair.of(
1106                     (resolvedUserId == mCurrentUserId) ? getClientStateLocked(userState) : 0,
1107                     client.mLastSentRelevantEventTypes);
1108         }
1109     }
1110 
1111     @Override
1112     @RequiresNoPermission
removeClient(IAccessibilityManagerClient callback, int userId)1113     public boolean removeClient(IAccessibilityManagerClient callback, int userId) {
1114         // TODO(b/190216606): Add tracing for removeClient when implementation is the same in master
1115 
1116         synchronized (mLock) {
1117             final int resolvedUserId = mSecurityPolicy
1118                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
1119 
1120             AccessibilityUserState userState = getUserStateLocked(resolvedUserId);
1121             if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
1122                 boolean unregistered = mGlobalClients.unregister(callback);
1123                 if (DEBUG) {
1124                     Slog.i(LOG_TAG,
1125                             "Removed global client for pid:" + Binder.getCallingPid() + "state: "
1126                                     + unregistered);
1127                 }
1128                 return unregistered;
1129             } else {
1130                 boolean unregistered = userState.mUserClients.unregister(callback);
1131                 if (DEBUG) {
1132                     Slog.i(LOG_TAG, "Removed user client for pid:" + Binder.getCallingPid()
1133                             + " and userId:" + resolvedUserId + "state: " + unregistered);
1134                 }
1135                 return unregistered;
1136             }
1137         }
1138     }
1139 
1140     @Override
1141     @RequiresNoPermission
sendAccessibilityEvent(AccessibilityEvent event, int userId)1142     public void sendAccessibilityEvent(AccessibilityEvent event, int userId) {
1143         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
1144             mTraceManager.logTrace(LOG_TAG + ".sendAccessibilityEvent", FLAGS_ACCESSIBILITY_MANAGER,
1145                     "event=" + event + ";userId=" + userId);
1146         }
1147         boolean dispatchEvent = false;
1148         int resolvedUserId;
1149 
1150         synchronized (mLock) {
1151             if (event.getWindowId() ==
1152                 AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID) {
1153                 // The replacer window isn't shown to services. Move its events into the pip.
1154                 AccessibilityWindowInfo pip = mA11yWindowManager.getPictureInPictureWindowLocked();
1155                 if (pip != null) {
1156                     int pipId = pip.getId();
1157                     event.setWindowId(pipId);
1158                 }
1159             }
1160 
1161             // We treat calls from a profile as if made by its parent as profiles
1162             // share the accessibility state of the parent. The call below
1163             // performs the current profile parent resolution.
1164             resolvedUserId = mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(userId);
1165 
1166             // Make sure the reported package is one the caller has access to.
1167             event.setPackageName(mSecurityPolicy.resolveValidReportedPackageLocked(
1168                     event.getPackageName(), UserHandle.getCallingAppId(), resolvedUserId,
1169                     getCallingPid()));
1170 
1171             // This method does nothing for a background user.
1172             if (resolvedUserId == mCurrentUserId) {
1173                 if (mSecurityPolicy.canDispatchAccessibilityEventLocked(mCurrentUserId, event)) {
1174                     mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(
1175                             mCurrentUserId, event.getWindowId(), event.getSourceNodeId(),
1176                             event.getEventType(), event.getAction());
1177                     mSecurityPolicy.updateEventSourceLocked(event);
1178                     dispatchEvent = true;
1179                 }
1180                 if (mHasInputFilter && mInputFilter != null) {
1181                     mMainHandler.sendMessage(obtainMessage(
1182                             AccessibilityManagerService::sendAccessibilityEventToInputFilter,
1183                             this, AccessibilityEvent.obtain(event)));
1184                 }
1185             }
1186         }
1187 
1188         if (dispatchEvent) {
1189             // Make sure clients receiving this event will be able to get the
1190             // current state of the windows as the window manager may be delaying
1191             // the computation for performance reasons.
1192             boolean shouldComputeWindows = false;
1193             int displayId = event.getDisplayId();
1194             final int windowId = event.getWindowId();
1195             if (windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID
1196                     && displayId == Display.INVALID_DISPLAY) {
1197                 displayId = mA11yWindowManager.getDisplayIdByUserIdAndWindowId(
1198                         resolvedUserId, windowId);
1199                 event.setDisplayId(displayId);
1200             }
1201             synchronized (mLock) {
1202                 if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
1203                         && displayId != Display.INVALID_DISPLAY
1204                         && mA11yWindowManager.isTrackingWindowsLocked(displayId)) {
1205                     shouldComputeWindows = true;
1206                 }
1207             }
1208             if (shouldComputeWindows) {
1209                 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL)) {
1210                     mTraceManager.logTrace("WindowManagerInternal.computeWindowsForAccessibility",
1211                             FLAGS_WINDOW_MANAGER_INTERNAL, "display=" + displayId);
1212                 }
1213                 final WindowManagerInternal wm = LocalServices.getService(
1214                         WindowManagerInternal.class);
1215                 wm.computeWindowsForAccessibility(displayId);
1216                 // The App side sends a event to notify that the window visible or focused,
1217                 // but the window information in framework is not updated yet, so we postpone it.
1218                 if (postponeWindowStateEvent(event)) {
1219                     return;
1220                 }
1221             }
1222 
1223             synchronized (mLock) {
1224                 dispatchAccessibilityEventLocked(event);
1225             }
1226         }
1227 
1228         if (OWN_PROCESS_ID != Binder.getCallingPid()) {
1229             event.recycle();
1230         }
1231     }
1232 
dispatchAccessibilityEventLocked(AccessibilityEvent event)1233     private void dispatchAccessibilityEventLocked(AccessibilityEvent event) {
1234         if (mProxyManager.isProxyedDisplay(event.getDisplayId())) {
1235             mProxyManager.sendAccessibilityEventLocked(event);
1236         } else {
1237             notifyAccessibilityServicesDelayedLocked(event, false);
1238             notifyAccessibilityServicesDelayedLocked(event, true);
1239         }
1240         mUiAutomationManager.sendAccessibilityEventLocked(event);
1241     }
1242 
sendAccessibilityEventToInputFilter(AccessibilityEvent event)1243     private void sendAccessibilityEventToInputFilter(AccessibilityEvent event) {
1244         synchronized (mLock) {
1245             if (mHasInputFilter && mInputFilter != null) {
1246                 mInputFilter.notifyAccessibilityEvent(event);
1247             }
1248         }
1249         event.recycle();
1250     }
1251 
1252     /**
1253      * This is the implementation of AccessibilityManager system API.
1254      * System UI calls into this method through AccessibilityManager system API to register a
1255      * system action.
1256      */
1257     @Override
1258     @EnforcePermission(MANAGE_ACCESSIBILITY)
registerSystemAction(RemoteAction action, int actionId)1259     public void registerSystemAction(RemoteAction action, int actionId) {
1260         registerSystemAction_enforcePermission();
1261         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
1262             mTraceManager.logTrace(LOG_TAG + ".registerSystemAction",
1263                     FLAGS_ACCESSIBILITY_MANAGER, "action=" + action + ";actionId=" + actionId);
1264         }
1265         getSystemActionPerformer().registerSystemAction(actionId, action);
1266     }
1267 
1268     /**
1269      * This is the implementation of AccessibilityManager system API.
1270      * System UI calls into this method through AccessibilityManager system API to unregister a
1271      * system action.
1272      */
1273     @Override
1274     @EnforcePermission(MANAGE_ACCESSIBILITY)
unregisterSystemAction(int actionId)1275     public void unregisterSystemAction(int actionId) {
1276         unregisterSystemAction_enforcePermission();
1277         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
1278             mTraceManager.logTrace(LOG_TAG + ".unregisterSystemAction",
1279                     FLAGS_ACCESSIBILITY_MANAGER, "actionId=" + actionId);
1280         }
1281 
1282         getSystemActionPerformer().unregisterSystemAction(actionId);
1283     }
1284 
getSystemActionPerformer()1285     private SystemActionPerformer getSystemActionPerformer() {
1286         if (mSystemActionPerformer == null) {
1287             mSystemActionPerformer =
1288                     new SystemActionPerformer(mContext, mWindowManagerService, null, this, this);
1289         }
1290         return mSystemActionPerformer;
1291     }
1292 
1293     @Override
1294     @RequiresNoPermission
getInstalledAccessibilityServiceList( int userId)1295     public ParceledListSlice<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(
1296             int userId) {
1297         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
1298             mTraceManager.logTrace(LOG_TAG + ".getInstalledAccessibilityServiceList",
1299                     FLAGS_ACCESSIBILITY_MANAGER, "userId=" + userId);
1300         }
1301 
1302         final int resolvedUserId;
1303         final List<AccessibilityServiceInfo> serviceInfos;
1304         synchronized (mLock) {
1305             final int deviceId = mProxyManager.getFirstDeviceIdForUidLocked(
1306                     Binder.getCallingUid());
1307             if (mProxyManager.isProxyedDeviceId(deviceId)) {
1308                 return new ParceledListSlice<>(
1309                         mProxyManager.getInstalledAndEnabledServiceInfosLocked(
1310                                 AccessibilityServiceInfo.FEEDBACK_ALL_MASK, deviceId));
1311             }
1312             // We treat calls from a profile as if made by its parent as profiles
1313             // share the accessibility state of the parent. The call below
1314             // performs the current profile parent resolution.
1315             resolvedUserId = mSecurityPolicy
1316                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
1317             serviceInfos = new ArrayList<>(
1318                     getUserStateLocked(resolvedUserId).mInstalledServices);
1319         }
1320 
1321         if (Binder.getCallingPid() == OWN_PROCESS_ID) {
1322             return new ParceledListSlice<>(serviceInfos);
1323         }
1324         final PackageManagerInternal pm = LocalServices.getService(
1325                 PackageManagerInternal.class);
1326         final int callingUid = Binder.getCallingUid();
1327         for (int i = serviceInfos.size() - 1; i >= 0; i--) {
1328             final AccessibilityServiceInfo serviceInfo = serviceInfos.get(i);
1329             if (pm.filterAppAccess(serviceInfo.getComponentName().getPackageName(), callingUid,
1330                     resolvedUserId)) {
1331                 serviceInfos.remove(i);
1332             }
1333         }
1334         return new ParceledListSlice<>(serviceInfos);
1335     }
1336 
1337     @Override
1338     @RequiresNoPermission
getEnabledAccessibilityServiceList(int feedbackType, int userId)1339     public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType,
1340             int userId) {
1341         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
1342             mTraceManager.logTrace(LOG_TAG + ".getEnabledAccessibilityServiceList",
1343                     FLAGS_ACCESSIBILITY_MANAGER,
1344                     "feedbackType=" + feedbackType + ";userId=" + userId);
1345         }
1346 
1347         synchronized (mLock) {
1348             final int deviceId = mProxyManager.getFirstDeviceIdForUidLocked(
1349                     Binder.getCallingUid());
1350             if (mProxyManager.isProxyedDeviceId(deviceId)) {
1351                 return mProxyManager.getInstalledAndEnabledServiceInfosLocked(feedbackType,
1352                         deviceId);
1353             }
1354             // We treat calls from a profile as if made by its parent as profiles
1355             // share the accessibility state of the parent. The call below
1356             // performs the current profile parent resolution.
1357             final int resolvedUserId = mSecurityPolicy
1358                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
1359 
1360             // The automation service can suppress other services.
1361             final AccessibilityUserState userState = getUserStateLocked(resolvedUserId);
1362             if (mUiAutomationManager.suppressingAccessibilityServicesLocked()) {
1363                 return Collections.emptyList();
1364             }
1365 
1366             final List<AccessibilityServiceConnection> services = userState.mBoundServices;
1367             final int serviceCount = services.size();
1368             final List<AccessibilityServiceInfo> result = new ArrayList<>(serviceCount);
1369             for (int i = 0; i < serviceCount; ++i) {
1370                 final AccessibilityServiceConnection service = services.get(i);
1371                 if ((service.mFeedbackType & feedbackType) != 0
1372                         || feedbackType == AccessibilityServiceInfo.FEEDBACK_ALL_MASK) {
1373                     result.add(service.getServiceInfo());
1374                 }
1375             }
1376             return result;
1377         }
1378     }
1379 
1380     @Override
1381     @RequiresNoPermission
interrupt(int userId)1382     public void interrupt(int userId) {
1383         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
1384             mTraceManager.logTrace(LOG_TAG + ".interrupt",
1385                     FLAGS_ACCESSIBILITY_MANAGER, "userId=" + userId);
1386         }
1387 
1388         List<IAccessibilityServiceClient> interfacesToInterrupt;
1389         synchronized (mLock) {
1390             // We treat calls from a profile as if made by its parent as profiles
1391             // share the accessibility state of the parent. The call below
1392             // performs the current profile parent resolution.
1393             final int resolvedUserId = mSecurityPolicy
1394                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
1395             // This method does nothing for a background user.
1396             if (resolvedUserId != mCurrentUserId) {
1397                 return;
1398             }
1399 
1400             final int deviceId = mProxyManager.getFirstDeviceIdForUidLocked(
1401                     Binder.getCallingUid());
1402             if (mProxyManager.isProxyedDeviceId(deviceId)) {
1403                 interfacesToInterrupt = new ArrayList<>();
1404                 mProxyManager.addServiceInterfacesLocked(interfacesToInterrupt, deviceId);
1405             } else {
1406                 List<AccessibilityServiceConnection> services =
1407                         getUserStateLocked(resolvedUserId).mBoundServices;
1408                 interfacesToInterrupt = new ArrayList<>(services.size());
1409                 for (int i = 0; i < services.size(); i++) {
1410                     AccessibilityServiceConnection service = services.get(i);
1411                     IBinder a11yServiceBinder = service.mService;
1412                     IAccessibilityServiceClient a11yServiceInterface = service.mServiceInterface;
1413                     if ((a11yServiceBinder != null) && (a11yServiceInterface != null)) {
1414                         interfacesToInterrupt.add(a11yServiceInterface);
1415                     }
1416                 }
1417             }
1418         }
1419         for (int i = 0, count = interfacesToInterrupt.size(); i < count; i++) {
1420             try {
1421                 if (mTraceManager.isA11yTracingEnabledForTypes(
1422                         FLAGS_ACCESSIBILITY_SERVICE_CLIENT)) {
1423                     mTraceManager.logTrace(LOG_TAG + ".IAccessibilityServiceClient.onInterrupt",
1424                             FLAGS_ACCESSIBILITY_SERVICE_CLIENT);
1425                 }
1426                 interfacesToInterrupt.get(i).onInterrupt();
1427             } catch (RemoteException re) {
1428                 Slog.e(LOG_TAG, "Error sending interrupt request to "
1429                         + interfacesToInterrupt.get(i), re);
1430             }
1431         }
1432     }
1433 
1434     @Override
1435     @RequiresNoPermission
addAccessibilityInteractionConnection(IWindow windowToken, IBinder leashToken, IAccessibilityInteractionConnection connection, String packageName, int userId)1436     public int addAccessibilityInteractionConnection(IWindow windowToken, IBinder leashToken,
1437             IAccessibilityInteractionConnection connection, String packageName,
1438             int userId) throws RemoteException {
1439         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
1440             mTraceManager.logTrace(LOG_TAG + ".addAccessibilityInteractionConnection",
1441                     FLAGS_ACCESSIBILITY_MANAGER,
1442                     "windowToken=" + windowToken + "leashToken=" + leashToken + ";connection="
1443                             + connection + "; packageName=" + packageName + ";userId=" + userId);
1444         }
1445 
1446         return mA11yWindowManager.addAccessibilityInteractionConnection(
1447                 windowToken, leashToken, connection, packageName, userId);
1448     }
1449 
1450     @Override
1451     @RequiresNoPermission
removeAccessibilityInteractionConnection(IWindow window)1452     public void removeAccessibilityInteractionConnection(IWindow window) {
1453         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
1454             mTraceManager.logTrace(LOG_TAG + ".removeAccessibilityInteractionConnection",
1455                     FLAGS_ACCESSIBILITY_MANAGER, "window=" + window);
1456         }
1457         mA11yWindowManager.removeAccessibilityInteractionConnection(window);
1458     }
1459 
1460     @Override
1461     @EnforcePermission(MODIFY_ACCESSIBILITY_DATA)
setPictureInPictureActionReplacingConnection( IAccessibilityInteractionConnection connection)1462     public void setPictureInPictureActionReplacingConnection(
1463             IAccessibilityInteractionConnection connection) throws RemoteException {
1464         setPictureInPictureActionReplacingConnection_enforcePermission();
1465         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
1466             mTraceManager.logTrace(LOG_TAG + ".setPictureInPictureActionReplacingConnection",
1467                     FLAGS_ACCESSIBILITY_MANAGER, "connection=" + connection);
1468         }
1469         mA11yWindowManager.setPictureInPictureActionReplacingConnection(connection);
1470     }
1471 
1472     @Override
1473     @EnforcePermission(RETRIEVE_WINDOW_CONTENT)
registerUiTestAutomationService(IBinder owner, IAccessibilityServiceClient serviceClient, AccessibilityServiceInfo accessibilityServiceInfo, int userId, int flags)1474     public void registerUiTestAutomationService(IBinder owner,
1475             IAccessibilityServiceClient serviceClient,
1476             AccessibilityServiceInfo accessibilityServiceInfo,
1477             int userId,
1478             int flags) {
1479         registerUiTestAutomationService_enforcePermission();
1480         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
1481             mTraceManager.logTrace(LOG_TAG + ".registerUiTestAutomationService",
1482                     FLAGS_ACCESSIBILITY_MANAGER,
1483                     "owner=" + owner + ";serviceClient=" + serviceClient
1484                     + ";accessibilityServiceInfo=" + accessibilityServiceInfo + ";flags=" + flags);
1485         }
1486 
1487         synchronized (mLock) {
1488             changeCurrentUserForTestAutomationIfNeededLocked(userId);
1489             mUiAutomationManager.registerUiTestAutomationServiceLocked(owner, serviceClient,
1490                     mContext, accessibilityServiceInfo, sIdCounter++, mMainHandler,
1491                     mSecurityPolicy, this, getTraceManager(), mWindowManagerService,
1492                     getSystemActionPerformer(), mA11yWindowManager, flags);
1493             onUserStateChangedLocked(getCurrentUserStateLocked());
1494         }
1495     }
1496 
1497     @Override
1498     @RequiresNoPermission
unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient)1499     public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) {
1500         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
1501             mTraceManager.logTrace(LOG_TAG + ".unregisterUiTestAutomationService",
1502                     FLAGS_ACCESSIBILITY_MANAGER, "serviceClient=" + serviceClient);
1503         }
1504         synchronized (mLock) {
1505             mUiAutomationManager.unregisterUiTestAutomationServiceLocked(serviceClient);
1506             restoreCurrentUserAfterTestAutomationIfNeededLocked();
1507         }
1508     }
1509 
1510     // TODO(b/255426725): temporary workaround to support visible background users for UiAutomation
1511     @GuardedBy("mLock")
changeCurrentUserForTestAutomationIfNeededLocked(@serIdInt int userId)1512     private void changeCurrentUserForTestAutomationIfNeededLocked(@UserIdInt int userId) {
1513         if (mVisibleBgUserIds == null) {
1514             Slogf.d(LOG_TAG, "changeCurrentUserForTestAutomationIfNeededLocked(%d): ignoring "
1515                     + "because device doesn't support visible background users", userId);
1516             return;
1517         }
1518         if (!mVisibleBgUserIds.get(userId)) {
1519             Slogf.wtf(LOG_TAG, "changeCurrentUserForTestAutomationIfNeededLocked(): cannot change "
1520                     + "current user to %d as it's not visible (mVisibleUsers=%s)",
1521                     userId, mVisibleBgUserIds);
1522             return;
1523         }
1524         if (mCurrentUserId == userId) {
1525             Slogf.d(LOG_TAG, "changeCurrentUserForTestAutomationIfNeededLocked(): NOT changing "
1526                     + "current user for test automation purposes as it is already %d",
1527                     mCurrentUserId);
1528             return;
1529         }
1530         Slogf.i(LOG_TAG, "changeCurrentUserForTestAutomationIfNeededLocked(): changing current user"
1531                 + " from %d to %d for test automation purposes", mCurrentUserId, userId);
1532         mRealCurrentUserId = mCurrentUserId;
1533         switchUser(userId);
1534     }
1535 
1536     // TODO(b/255426725): temporary workaround to support visible background users for UiAutomation
1537     @GuardedBy("mLock")
restoreCurrentUserAfterTestAutomationIfNeededLocked()1538     private void restoreCurrentUserAfterTestAutomationIfNeededLocked() {
1539         if (mVisibleBgUserIds == null) {
1540             Slogf.d(LOG_TAG, "restoreCurrentUserForTestAutomationIfNeededLocked(): ignoring "
1541                     + "because device doesn't support visible background users");
1542             return;
1543         }
1544         if (mRealCurrentUserId == UserHandle.USER_CURRENT) {
1545             Slogf.d(LOG_TAG, "restoreCurrentUserForTestAutomationIfNeededLocked(): ignoring "
1546                     + "because mRealCurrentUserId is already USER_CURRENT");
1547             return;
1548         }
1549         Slogf.i(LOG_TAG, "restoreCurrentUserForTestAutomationIfNeededLocked(): restoring current "
1550                 + "user to %d after using %d for test automation purposes",
1551                 mRealCurrentUserId, mCurrentUserId);
1552         int currentUserId = mRealCurrentUserId;
1553         mRealCurrentUserId = UserHandle.USER_CURRENT;
1554         switchUser(currentUserId);
1555     }
1556 
1557     @Override
1558     @EnforcePermission(RETRIEVE_WINDOW_CONTENT)
getWindowToken(int windowId, int userId)1559     public IBinder getWindowToken(int windowId, int userId) {
1560         getWindowToken_enforcePermission();
1561         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
1562             mTraceManager.logTrace(LOG_TAG + ".getWindowToken",
1563                     FLAGS_ACCESSIBILITY_MANAGER, "windowId=" + windowId + ";userId=" + userId);
1564         }
1565 
1566         synchronized (mLock) {
1567             // We treat calls from a profile as if made by its parent as profiles
1568             // share the accessibility state of the parent. The call below
1569             // performs the current profile parent resolution.
1570             final int resolvedUserId = mSecurityPolicy
1571                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
1572             if (resolvedUserId != mCurrentUserId) {
1573                 return null;
1574             }
1575             final AccessibilityWindowInfo accessibilityWindowInfo = mA11yWindowManager
1576                     .findA11yWindowInfoByIdLocked(windowId);
1577             if (accessibilityWindowInfo == null) {
1578                 return null;
1579             }
1580             // We use AccessibilityWindowInfo#getId instead of windowId. When the windowId comes
1581             // from an embedded hierarchy, the system can't find correct window token because
1582             // embedded hierarchy doesn't have windowInfo. Calling
1583             // AccessibilityWindowManager#findA11yWindowInfoByIdLocked can look for its parent's
1584             // windowInfo, so it is safer to use AccessibilityWindowInfo#getId
1585             // to get window token to find real window.
1586             return mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(userId,
1587                     accessibilityWindowInfo.getId());
1588         }
1589     }
1590 
1591     /**
1592      * Invoked remotely over AIDL by SysUi when the accessibility button within the system's
1593      * navigation area has been clicked.
1594      *
1595      * @param displayId The logical display id.
1596      * @param targetName The flattened {@link ComponentName} string or the class name of a system
1597      *        class implementing a supported accessibility feature, or {@code null} if there's no
1598      *        specified target.
1599      */
1600     @Override
1601     @EnforcePermission(STATUS_BAR_SERVICE)
notifyAccessibilityButtonClicked(int displayId, String targetName)1602     public void notifyAccessibilityButtonClicked(int displayId, String targetName) {
1603         notifyAccessibilityButtonClicked_enforcePermission();
1604         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
1605             mTraceManager.logTrace(LOG_TAG + ".notifyAccessibilityButtonClicked",
1606                     FLAGS_ACCESSIBILITY_MANAGER,
1607                     "displayId=" + displayId + ";targetName=" + targetName);
1608         }
1609 
1610         if (targetName == null) {
1611             synchronized (mLock) {
1612                 final AccessibilityUserState userState = getCurrentUserStateLocked();
1613                 targetName = userState.getTargetAssignedToAccessibilityButton();
1614             }
1615         }
1616         mMainHandler.sendMessage(obtainMessage(
1617                 AccessibilityManagerService::performAccessibilityShortcutInternal, this,
1618                 displayId, UserShortcutType.SOFTWARE, targetName));
1619     }
1620 
1621     /**
1622      * Invoked remotely over AIDL by SysUi when the visibility of the accessibility
1623      * button within the system's navigation area has changed.
1624      *
1625      * @param shown {@code true} if the accessibility button is shown to the
1626      *                  user, {@code false} otherwise
1627      */
1628     @Override
1629     @EnforcePermission(STATUS_BAR_SERVICE)
notifyAccessibilityButtonVisibilityChanged(boolean shown)1630     public void notifyAccessibilityButtonVisibilityChanged(boolean shown) {
1631         notifyAccessibilityButtonVisibilityChanged_enforcePermission();
1632         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
1633             mTraceManager.logTrace(LOG_TAG + ".notifyAccessibilityButtonVisibilityChanged",
1634                     FLAGS_ACCESSIBILITY_MANAGER, "shown=" + shown);
1635         }
1636 
1637         synchronized (mLock) {
1638             notifyAccessibilityButtonVisibilityChangedLocked(shown);
1639         }
1640     }
1641 
1642     @Override
1643     @EnforcePermission(allOf = { STATUS_BAR_SERVICE, MANAGE_ACCESSIBILITY })
notifyQuickSettingsTilesChanged( @serIdInt int userId, @NonNull List<ComponentName> tileComponentNames)1644     public void notifyQuickSettingsTilesChanged(
1645             @UserIdInt int userId, @NonNull List<ComponentName> tileComponentNames) {
1646         notifyQuickSettingsTilesChanged_enforcePermission();
1647         if (!android.view.accessibility.Flags.a11yQsShortcut()) {
1648             return;
1649         }
1650         if (DEBUG) {
1651             Slog.d(LOG_TAG, TextUtils.formatSimple(
1652                     "notifyQuickSettingsTilesChanged userId: %d, tileComponentNames: %s",
1653                     userId, tileComponentNames));
1654         }
1655         final Set<ComponentName> newTileComponentNames = new ArraySet<>(tileComponentNames);
1656         final Set<ComponentName> addedTiles;
1657         final Set<ComponentName> removedTiles;
1658         final Map<ComponentName, AccessibilityServiceInfo> tileServiceToA11yServiceInfo;
1659         final Map<ComponentName, ComponentName> a11yFeatureToTileService;
1660 
1661         // update in-memory copy of QS_TILES in AccessibilityManager
1662         synchronized (mLock) {
1663             AccessibilityUserState userState = getUserStateLocked(userId);
1664 
1665             tileServiceToA11yServiceInfo = userState.getTileServiceToA11yServiceInfoMapLocked();
1666             a11yFeatureToTileService = userState.getA11yFeatureToTileService();
1667 
1668             ArraySet<ComponentName> currentTiles = userState.getA11yQsTilesInQsPanel();
1669             // Find newly added tiles
1670             addedTiles = newTileComponentNames
1671                     .stream()
1672                     .filter(tileComponentName -> !currentTiles.contains(tileComponentName))
1673                     .collect(Collectors.toSet());
1674             // Find newly removed tiles
1675             removedTiles = currentTiles
1676                     .stream()
1677                     .filter(tileComponentName -> !newTileComponentNames.contains(tileComponentName))
1678                     .collect(Collectors.toSet());
1679 
1680             if (addedTiles.isEmpty() && removedTiles.isEmpty()) {
1681                 return;
1682             }
1683 
1684             userState.updateA11yTilesInQsPanelLocked(newTileComponentNames);
1685         }
1686 
1687         List<String> a11yFeaturesToEnable = new ArrayList<>();
1688         List<String> a11yFeaturesToRemove = new ArrayList<>();
1689         // Find the framework features to configure the qs shortcut on/off
1690         for (Map.Entry<ComponentName, ComponentName> frameworkFeatureWithTile :
1691                 ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE.entrySet()) {
1692             String a11yFeature = frameworkFeatureWithTile.getKey().flattenToString();
1693             ComponentName tile = frameworkFeatureWithTile.getValue();
1694             if (addedTiles.contains(tile)) {
1695                 a11yFeaturesToEnable.add(a11yFeature);
1696             } else if (removedTiles.contains(tile)) {
1697                 a11yFeaturesToRemove.add(a11yFeature);
1698             }
1699         }
1700         // Find the accessibility service/activity to configure the qs shortcut on/off
1701         for (Map.Entry<ComponentName, ComponentName> a11yFeatureWithTileService :
1702                 a11yFeatureToTileService.entrySet()) {
1703             String a11yFeature = a11yFeatureWithTileService.getKey().flattenToString();
1704             ComponentName tileService = a11yFeatureWithTileService.getValue();
1705             if (addedTiles.contains(tileService)) {
1706                 AccessibilityServiceInfo serviceInfo = tileServiceToA11yServiceInfo.getOrDefault(
1707                         tileService, null);
1708                 if (serviceInfo != null && isAccessibilityServiceWarningRequired(serviceInfo)) {
1709                     // TODO(b/314850435): show full device control warning if needed after
1710                     // SysUI QS Panel can update live
1711                     // The user attempts to add QS shortcut in QS Panel, but we don't actually
1712                     // turn on the shortcut due to lack of full device control permission
1713                     logMetricForQsShortcutConfiguration(/* enable= */ true, /* numOfFeatures= */ 1);
1714                     continue;
1715                 }
1716                 a11yFeaturesToEnable.add(a11yFeature);
1717             } else if (removedTiles.contains(tileService)) {
1718                 a11yFeaturesToRemove.add(a11yFeature);
1719             }
1720         }
1721         // Turn on/off a11y qs shortcut for the a11y features based on the change in QS Panel
1722         if (!a11yFeaturesToEnable.isEmpty()) {
1723             enableShortcutForTargets(/* enable= */ true, UserShortcutType.QUICK_SETTINGS,
1724                     a11yFeaturesToEnable, userId);
1725         }
1726 
1727         if (!a11yFeaturesToRemove.isEmpty()) {
1728             enableShortcutForTargets(/* enable= */ false, UserShortcutType.QUICK_SETTINGS,
1729                     a11yFeaturesToRemove, userId);
1730         }
1731     }
1732 
1733     /**
1734      * Called when a gesture is detected on a display by the framework.
1735      *
1736      * @param gestureEvent the detail of the gesture.
1737      * @return true if the event is handled.
1738      */
onGesture(AccessibilityGestureEvent gestureEvent)1739     public boolean onGesture(AccessibilityGestureEvent gestureEvent) {
1740         synchronized (mLock) {
1741             boolean handled = notifyGestureLocked(gestureEvent, false);
1742             if (!handled) {
1743                 handled = notifyGestureLocked(gestureEvent, true);
1744             }
1745             return handled;
1746         }
1747     }
1748 
1749     /** Send a motion event to the services. */
sendMotionEventToListeningServices(MotionEvent event)1750     public boolean sendMotionEventToListeningServices(MotionEvent event) {
1751         boolean result;
1752         event = MotionEvent.obtain(event);
1753         if (DEBUG) {
1754             Slog.d(LOG_TAG, "Sending event to service: " + event);
1755         }
1756         result = scheduleNotifyMotionEvent(event);
1757         return result;
1758     }
1759 
1760     /**
1761      * Notifies services that the touch state on a given display has changed.
1762      */
onTouchStateChanged(int displayId, int state)1763     public boolean onTouchStateChanged(int displayId, int state) {
1764             if (DEBUG) {
1765                 Slog.d(LOG_TAG, "Notifying touch state:"
1766                         + TouchInteractionController.stateToString(state));
1767             }
1768         return scheduleNotifyTouchState(displayId, state);
1769     }
1770 
1771     /**
1772      * Called when the system action list is changed.
1773      */
1774     @Override
onSystemActionsChanged()1775     public void onSystemActionsChanged() {
1776         synchronized (mLock) {
1777             AccessibilityUserState state = getCurrentUserStateLocked();
1778             notifySystemActionsChangedLocked(state);
1779         }
1780     }
1781 
1782     @Override
1783     // TODO(b/276459590): Remove when this is resolved at the virtual device/input level.
moveNonProxyTopFocusedDisplayToTopIfNeeded()1784     public void moveNonProxyTopFocusedDisplayToTopIfNeeded() {
1785         mA11yWindowManager.moveNonProxyTopFocusedDisplayToTopIfNeeded();
1786     }
1787 
1788     @Override
1789     // TODO(b/276459590): Remove when this is resolved at the virtual device/input level.
getLastNonProxyTopFocusedDisplayId()1790     public int getLastNonProxyTopFocusedDisplayId() {
1791         return mA11yWindowManager.getLastNonProxyTopFocusedDisplayId();
1792     }
1793 
1794     @VisibleForTesting
notifySystemActionsChangedLocked(AccessibilityUserState userState)1795     void notifySystemActionsChangedLocked(AccessibilityUserState userState) {
1796         for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
1797             AccessibilityServiceConnection service = userState.mBoundServices.get(i);
1798             service.notifySystemActionsChangedLocked();
1799         }
1800     }
1801 
1802     @VisibleForTesting
notifyKeyEvent(KeyEvent event, int policyFlags)1803     public boolean notifyKeyEvent(KeyEvent event, int policyFlags) {
1804         synchronized (mLock) {
1805             List<AccessibilityServiceConnection> boundServices =
1806                     getCurrentUserStateLocked().mBoundServices;
1807             if (boundServices.isEmpty()) {
1808                 return false;
1809             }
1810             return getKeyEventDispatcher().notifyKeyEventLocked(event, policyFlags, boundServices);
1811         }
1812     }
1813 
1814     /**
1815      * Called by the MagnificationController when the state of display
1816      * magnification changes.
1817      *
1818      * <p>
1819      * It can notify window magnification change if the service supports controlling all the
1820      * magnification mode.
1821      * </p>
1822      *
1823      * @param displayId The logical display id
1824      * @param region The magnification region.
1825      *               If the config mode is
1826      *               {@link MagnificationConfig#MAGNIFICATION_MODE_FULLSCREEN},
1827      *               it is the region of the screen currently active for magnification.
1828      *               the returned region will be empty if the magnification is not active
1829      *               (e.g. scale is 1. And the magnification is active if magnification
1830      *               gestures are enabled or if a service is running that can control
1831      *               magnification.
1832      *               If the config mode is
1833      *               {@link MagnificationConfig#MAGNIFICATION_MODE_WINDOW},
1834      *               it is the region of screen projected on the magnification window.
1835      *               The region will be empty if magnification is not activated.
1836      * @param config The magnification config. That has magnification mode, the new scale and the
1837      *              new screen-relative center position
1838      */
notifyMagnificationChanged(int displayId, @NonNull Region region, @NonNull MagnificationConfig config)1839     public void notifyMagnificationChanged(int displayId, @NonNull Region region,
1840             @NonNull MagnificationConfig config) {
1841         synchronized (mLock) {
1842             notifyClearAccessibilityCacheLocked();
1843             notifyMagnificationChangedLocked(displayId, region, config);
1844         }
1845     }
1846 
1847     /**
1848      * Called by AccessibilityInputFilter when it creates or destroys the motionEventInjector.
1849      * Not using a getter because the AccessibilityInputFilter isn't thread-safe
1850      *
1851      * @param motionEventInjectors The array of motionEventInjectors. May be null.
1852      *
1853      */
setMotionEventInjectors(SparseArray<MotionEventInjector> motionEventInjectors)1854     void setMotionEventInjectors(SparseArray<MotionEventInjector> motionEventInjectors) {
1855         synchronized (mLock) {
1856             mMotionEventInjectors = motionEventInjectors;
1857             // We may be waiting on this object being set
1858             mLock.notifyAll();
1859         }
1860     }
1861 
1862     @Override
getMotionEventInjectorForDisplayLocked(int displayId)1863     public @Nullable MotionEventInjector getMotionEventInjectorForDisplayLocked(int displayId) {
1864         final long endMillis = SystemClock.uptimeMillis() + WAIT_INPUT_FILTER_INSTALL_TIMEOUT_MS;
1865         MotionEventInjector motionEventInjector = null;
1866         while ((mMotionEventInjectors == null) && (SystemClock.uptimeMillis() < endMillis)) {
1867             try {
1868                 mLock.wait(endMillis - SystemClock.uptimeMillis());
1869             } catch (InterruptedException ie) {
1870                 /* ignore */
1871             }
1872         }
1873         if (mMotionEventInjectors == null) {
1874             Slog.e(LOG_TAG, "MotionEventInjector installation timed out");
1875         } else {
1876             motionEventInjector = mMotionEventInjectors.get(displayId);
1877         }
1878         return motionEventInjector;
1879     }
1880 
1881     /**
1882      * Gets a point within the accessibility focused node where we can send down
1883      * and up events to perform a click.
1884      *
1885      * @param outPoint The click point to populate.
1886      * @return Whether accessibility a click point was found and set.
1887      */
1888     // TODO: (multi-display) Make sure this works for multiple displays.
getAccessibilityFocusClickPointInScreen(Point outPoint)1889     public boolean getAccessibilityFocusClickPointInScreen(Point outPoint) {
1890         return getInteractionBridge().getAccessibilityFocusClickPointInScreenNotLocked(outPoint);
1891     }
1892 
1893     /**
1894      * Perform an accessibility action on the view that currently has accessibility focus.
1895      * Has no effect if no item has accessibility focus, if the item with accessibility
1896      * focus does not expose the specified action, or if the action fails.
1897      *
1898      * @param action The action to perform.
1899      *
1900      * @return {@code true} if the action was performed. {@code false} if it was not.
1901      */
performActionOnAccessibilityFocusedItem( AccessibilityNodeInfo.AccessibilityAction action)1902     public boolean performActionOnAccessibilityFocusedItem(
1903             AccessibilityNodeInfo.AccessibilityAction action) {
1904         return getInteractionBridge().performActionOnAccessibilityFocusedItemNotLocked(action);
1905     }
1906 
1907     /**
1908      * Returns true if accessibility focus is confined to the active window.
1909      */
accessibilityFocusOnlyInActiveWindow()1910     public boolean accessibilityFocusOnlyInActiveWindow() {
1911         synchronized (mLock) {
1912             return mA11yWindowManager.accessibilityFocusOnlyInActiveWindowLocked();
1913         }
1914     }
1915 
1916     /**
1917      * Gets the bounds of a window.
1918      *
1919      * @param outBounds The output to which to write the bounds.
1920      */
getWindowBounds(int windowId, Rect outBounds)1921     boolean getWindowBounds(int windowId, Rect outBounds) {
1922         IBinder token;
1923         synchronized (mLock) {
1924             token = getWindowToken(windowId, mCurrentUserId);
1925         }
1926         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL)) {
1927             mTraceManager.logTrace("WindowManagerInternal.getWindowFrame",
1928                     FLAGS_WINDOW_MANAGER_INTERNAL, "token=" + token + ";outBounds=" + outBounds);
1929         }
1930         mWindowManagerService.getWindowFrame(token, outBounds);
1931         if (!outBounds.isEmpty()) {
1932             return true;
1933         }
1934         return false;
1935     }
1936 
getActiveWindowId()1937     public int getActiveWindowId() {
1938         return mA11yWindowManager.getActiveWindowId(mCurrentUserId);
1939     }
1940 
onTouchInteractionStart()1941     public void onTouchInteractionStart() {
1942         mA11yWindowManager.onTouchInteractionStart();
1943     }
1944 
onTouchInteractionEnd()1945     public void onTouchInteractionEnd() {
1946         mA11yWindowManager.onTouchInteractionEnd();
1947     }
1948 
1949     @VisibleForTesting
switchUser(int userId)1950     void switchUser(int userId) {
1951         mMagnificationController.updateUserIdIfNeeded(userId);
1952         List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos = null;
1953         List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos = null;
1954         parsedAccessibilityServiceInfos = parseAccessibilityServiceInfos(userId);
1955         parsedAccessibilityShortcutInfos = parseAccessibilityShortcutInfos(userId);
1956         synchronized (mLock) {
1957             if (mCurrentUserId == userId && mInitialized) {
1958                 return;
1959             }
1960 
1961             // Disconnect from services for the old user.
1962             AccessibilityUserState oldUserState = getCurrentUserStateLocked();
1963             oldUserState.onSwitchToAnotherUserLocked();
1964 
1965             // Disable the local managers for the old user.
1966             if (oldUserState.mUserClients.getRegisteredCallbackCount() > 0) {
1967                 mMainHandler.sendMessage(obtainMessage(
1968                         AccessibilityManagerService::sendStateToClients,
1969                         this, 0, oldUserState.mUserId));
1970             }
1971 
1972             // Announce user changes only if more that one exist.
1973             UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1974             final boolean announceNewUser = userManager.getUsers().size() > 1;
1975 
1976             // The user changed.
1977             mCurrentUserId = userId;
1978             AccessibilityUserState userState = getCurrentUserStateLocked();
1979 
1980             readConfigurationForUserStateLocked(userState,
1981                     parsedAccessibilityServiceInfos, parsedAccessibilityShortcutInfos);
1982             mSecurityPolicy.onSwitchUserLocked(mCurrentUserId, userState.mEnabledServices);
1983             // Even if reading did not yield change, we have to update
1984             // the state since the context in which the current user
1985             // state was used has changed since it was inactive.
1986             onUserStateChangedLocked(userState);
1987             // It's better to have this migration in SettingsProvider. Unfortunately,
1988             // SettingsProvider migrated database in a very early stage which A11yManagerService
1989             // haven't finished or started the initialization. We cannot get enough information from
1990             // A11yManagerService to execute these migrations in SettingsProvider. Passing 0 for
1991             // restoreFromSdkInt to have this migration check execute every time, because we did not
1992             // find out a way to detect the device finished the OTA and switch the user.
1993             migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null,
1994                     /* restoreFromSdkInt = */0);
1995             // Package components are disabled per user, so secondary users also need their migrated
1996             // Accessibility Menu component disabled.
1997             disableAccessibilityMenuToMigrateIfNeeded();
1998 
1999             if (announceNewUser) {
2000                 // Schedule announcement of the current user if needed.
2001                 mMainHandler.sendMessageDelayed(
2002                         obtainMessage(AccessibilityManagerService::announceNewUserIfNeeded, this),
2003                         WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS);
2004             }
2005         }
2006     }
2007 
announceNewUserIfNeeded()2008     private void announceNewUserIfNeeded() {
2009         synchronized (mLock) {
2010             AccessibilityUserState userState = getCurrentUserStateLocked();
2011             if (userState.isHandlingAccessibilityEventsLocked()) {
2012                 UserManager userManager = (UserManager) mContext.getSystemService(
2013                         Context.USER_SERVICE);
2014                 String message = mContext.getString(R.string.user_switched,
2015                         userManager.getUserInfo(mCurrentUserId).name);
2016                 AccessibilityEvent event = AccessibilityEvent.obtain(
2017                         AccessibilityEvent.TYPE_ANNOUNCEMENT);
2018                 event.getText().add(message);
2019                 sendAccessibilityEventLocked(event, mCurrentUserId);
2020             }
2021         }
2022     }
2023 
unlockUser(int userId)2024     private void unlockUser(int userId) {
2025         synchronized (mLock) {
2026             int parentUserId = mSecurityPolicy.resolveProfileParentLocked(userId);
2027             if (parentUserId == mCurrentUserId) {
2028                 AccessibilityUserState userState = getUserStateLocked(mCurrentUserId);
2029                 onUserStateChangedLocked(userState);
2030             }
2031         }
2032     }
2033 
removeUser(int userId)2034     private void removeUser(int userId) {
2035         synchronized (mLock) {
2036             mUserStates.remove(userId);
2037         }
2038         getMagnificationController().onUserRemoved(userId);
2039     }
2040 
2041     // Called only during settings restore; currently supports only the owner user
2042     // TODO: http://b/22388012
restoreEnabledAccessibilityServicesLocked(String oldSetting, String newSetting, int restoreFromSdkInt)2043     void restoreEnabledAccessibilityServicesLocked(String oldSetting, String newSetting,
2044             int restoreFromSdkInt) {
2045         readComponentNamesFromStringLocked(oldSetting, mTempComponentNameSet, false);
2046         readComponentNamesFromStringLocked(newSetting, mTempComponentNameSet, true);
2047 
2048         AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM);
2049         userState.mEnabledServices.clear();
2050         userState.mEnabledServices.addAll(mTempComponentNameSet);
2051         persistComponentNamesToSettingLocked(
2052                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
2053                 userState.mEnabledServices,
2054                 UserHandle.USER_SYSTEM);
2055         onUserStateChangedLocked(userState);
2056         migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null, restoreFromSdkInt);
2057     }
2058 
2059     /**
2060      * User could enable accessibility services and configure accessibility button during the SUW.
2061      * Merges current value of accessibility button settings into the restored one to make sure
2062      * user's preferences of accessibility button updated in SUW are not lost.
2063      *
2064      * Called only during settings restore; currently supports only the owner user
2065      * TODO: http://b/22388012
2066      */
restoreAccessibilityButtonTargetsLocked(String oldSetting, String newSetting)2067     void restoreAccessibilityButtonTargetsLocked(String oldSetting, String newSetting) {
2068         final Set<String> targetsFromSetting = new ArraySet<>();
2069         readColonDelimitedStringToSet(oldSetting, str -> str, targetsFromSetting,
2070                 /* doMerge = */false);
2071         readColonDelimitedStringToSet(newSetting, str -> str, targetsFromSetting,
2072                 /* doMerge = */true);
2073 
2074         final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM);
2075         userState.mAccessibilityButtonTargets.clear();
2076         userState.mAccessibilityButtonTargets.addAll(targetsFromSetting);
2077         persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
2078                 UserHandle.USER_SYSTEM, userState.mAccessibilityButtonTargets, str -> str);
2079 
2080         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
2081         onUserStateChangedLocked(userState);
2082     }
2083 
2084     /**
2085      * User could configure accessibility shortcut during the SUW before restoring user data.
2086      * Merges the current value and the new value to make sure we don't lost the setting the user's
2087      * preferences of accessibility qs shortcut updated in SUW are not lost.
2088      *
2089      * Called only during settings restore; currently supports only the owner user
2090      * TODO: http://b/22388012
2091      */
restoreAccessibilityQsTargets(String newValue)2092     private void restoreAccessibilityQsTargets(String newValue) {
2093         synchronized (mLock) {
2094             final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM);
2095             final Set<String> mergedTargets = userState.getA11yQsTargets();
2096             readColonDelimitedStringToSet(newValue, str -> str, mergedTargets,
2097                     /* doMerge = */ true);
2098 
2099             userState.updateA11yQsTargetLocked(mergedTargets);
2100             persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_QS_TARGETS,
2101                     UserHandle.USER_SYSTEM, mergedTargets, str -> str);
2102             scheduleNotifyClientsOfServicesStateChangeLocked(userState);
2103             onUserStateChangedLocked(userState);
2104         }
2105     }
2106 
2107     /**
2108      * Merges the old and restored value of
2109      * {@link Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE}.
2110      *
2111      * <p>Also clears out {@link R.string#config_defaultAccessibilityService} from
2112      * the merged set if it was not present before restoring.
2113      */
restoreAccessibilityShortcutTargetService( String oldValue, String restoredValue)2114     private void restoreAccessibilityShortcutTargetService(
2115             String oldValue, String restoredValue) {
2116         final Set<String> targetsFromSetting = new ArraySet<>();
2117         readColonDelimitedStringToSet(oldValue, str -> str,
2118                 targetsFromSetting, /*doMerge=*/false);
2119         final String defaultService =
2120                 mContext.getString(R.string.config_defaultAccessibilityService);
2121         final ComponentName defaultServiceComponent = TextUtils.isEmpty(defaultService)
2122                 ? null : ComponentName.unflattenFromString(defaultService);
2123         boolean shouldClearDefaultService = defaultServiceComponent != null
2124                 && !stringSetContainsComponentName(targetsFromSetting, defaultServiceComponent);
2125         readColonDelimitedStringToSet(restoredValue, str -> str,
2126                 targetsFromSetting, /*doMerge=*/true);
2127         if (Flags.clearDefaultFromA11yShortcutTargetServiceRestore()) {
2128             if (shouldClearDefaultService && stringSetContainsComponentName(
2129                     targetsFromSetting, defaultServiceComponent)) {
2130                 Slog.i(LOG_TAG, "Removing default service " + defaultService
2131                         + " from restore of "
2132                         + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
2133                 targetsFromSetting.removeIf(str ->
2134                         defaultServiceComponent.equals(ComponentName.unflattenFromString(str)));
2135             }
2136             if (targetsFromSetting.isEmpty()) {
2137                 return;
2138             }
2139         }
2140         synchronized (mLock) {
2141             final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM);
2142             final Set<String> shortcutTargets =
2143                     userState.getShortcutTargetsLocked(UserShortcutType.HARDWARE);
2144             shortcutTargets.clear();
2145             shortcutTargets.addAll(targetsFromSetting);
2146             persistColonDelimitedSetToSettingLocked(
2147                     Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
2148                     UserHandle.USER_SYSTEM, targetsFromSetting, str -> str);
2149             scheduleNotifyClientsOfServicesStateChangeLocked(userState);
2150             onUserStateChangedLocked(userState);
2151         }
2152     }
2153 
2154     /**
2155      * Returns {@code true} if the set contains the provided non-null {@link ComponentName}.
2156      *
2157      * <p>This ignores values in the set that are not valid {@link ComponentName}s.
2158      */
stringSetContainsComponentName(Set<String> set, @NonNull ComponentName componentName)2159     private boolean stringSetContainsComponentName(Set<String> set,
2160             @NonNull ComponentName componentName) {
2161         return componentName != null && set.stream()
2162                 .map(ComponentName::unflattenFromString)
2163                 .anyMatch(componentName::equals);
2164     }
2165 
getClientStateLocked(AccessibilityUserState userState)2166     private int getClientStateLocked(AccessibilityUserState userState) {
2167         return userState.getClientStateLocked(
2168             mUiAutomationManager.canIntrospect(),
2169             mTraceManager.getTraceStateForAccessibilityManagerClientState());
2170     }
2171 
getInteractionBridge()2172     private InteractionBridge getInteractionBridge() {
2173         synchronized (mLock) {
2174             if (mInteractionBridge == null) {
2175                 mInteractionBridge = new InteractionBridge();
2176             }
2177             return mInteractionBridge;
2178         }
2179     }
2180 
notifyGestureLocked(AccessibilityGestureEvent gestureEvent, boolean isDefault)2181     private boolean notifyGestureLocked(AccessibilityGestureEvent gestureEvent, boolean isDefault) {
2182         // TODO: Now we are giving the gestures to the last enabled
2183         //       service that can handle them which is the last one
2184         //       in our list since we write the last enabled as the
2185         //       last record in the enabled services setting. Ideally,
2186         //       the user should make the call which service handles
2187         //       gestures. However, only one service should handle
2188         //       gestures to avoid user frustration when different
2189         //       behavior is observed from different combinations of
2190         //       enabled accessibility services.
2191         AccessibilityUserState state = getCurrentUserStateLocked();
2192         for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
2193             AccessibilityServiceConnection service = state.mBoundServices.get(i);
2194             if (service.mRequestTouchExplorationMode && service.mIsDefault == isDefault) {
2195                 service.notifyGesture(gestureEvent);
2196                 return true;
2197             }
2198         }
2199         return false;
2200     }
2201 
scheduleNotifyMotionEvent(MotionEvent event)2202     private boolean scheduleNotifyMotionEvent(MotionEvent event) {
2203         boolean result = false;
2204         int displayId = event.getDisplayId();
2205         synchronized (mLock) {
2206             AccessibilityUserState state = getCurrentUserStateLocked();
2207             for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
2208                 AccessibilityServiceConnection service = state.mBoundServices.get(i);
2209                 if (service.wantsGenericMotionEvent(event)
2210                         || (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)
2211                         && service.isServiceDetectsGesturesEnabled(displayId))) {
2212                     service.notifyMotionEvent(event);
2213                     result = true;
2214                 }
2215             }
2216         }
2217         return result;
2218     }
2219 
scheduleNotifyTouchState(int displayId, int touchState)2220     private boolean scheduleNotifyTouchState(int displayId, int touchState) {
2221         boolean result = false;
2222         synchronized (mLock) {
2223             AccessibilityUserState state = getCurrentUserStateLocked();
2224             for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
2225                 AccessibilityServiceConnection service = state.mBoundServices.get(i);
2226                 if (service.isServiceDetectsGesturesEnabled(displayId)) {
2227                     service.notifyTouchState(displayId, touchState);
2228                     result = true;
2229                 }
2230             }
2231         }
2232         return result;
2233     }
2234 
2235     @Override
notifyClearAccessibilityCacheLocked()2236     public void notifyClearAccessibilityCacheLocked() {
2237         AccessibilityUserState state = getCurrentUserStateLocked();
2238         for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
2239             AccessibilityServiceConnection service = state.mBoundServices.get(i);
2240             service.notifyClearAccessibilityNodeInfoCache();
2241         }
2242 
2243         mProxyManager.clearCacheLocked();
2244     }
2245 
notifyMagnificationChangedLocked(int displayId, @NonNull Region region, @NonNull MagnificationConfig config)2246     private void notifyMagnificationChangedLocked(int displayId, @NonNull Region region,
2247             @NonNull MagnificationConfig config) {
2248         final AccessibilityUserState state = getCurrentUserStateLocked();
2249         for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
2250             final AccessibilityServiceConnection service = state.mBoundServices.get(i);
2251             service.notifyMagnificationChangedLocked(displayId, region, config);
2252         }
2253     }
2254 
sendAccessibilityButtonToInputFilter(int displayId)2255     private void sendAccessibilityButtonToInputFilter(int displayId) {
2256         synchronized (mLock) {
2257             if (mHasInputFilter && mInputFilter != null) {
2258                 mInputFilter.notifyAccessibilityButtonClicked(displayId);
2259             }
2260         }
2261     }
2262 
showAccessibilityTargetsSelection(int displayId, @UserShortcutType int shortcutType)2263     private void showAccessibilityTargetsSelection(int displayId,
2264             @UserShortcutType int shortcutType) {
2265         final Intent intent = new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
2266         final String chooserClassName = (shortcutType == UserShortcutType.HARDWARE)
2267                 ? AccessibilityShortcutChooserActivity.class.getName()
2268                 : AccessibilityButtonChooserActivity.class.getName();
2269         intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName);
2270         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
2271         final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
2272         mContext.startActivityAsUser(intent, bundle, UserHandle.of(mCurrentUserId));
2273     }
2274 
launchShortcutTargetActivity(int displayId, ComponentName name)2275     private void launchShortcutTargetActivity(int displayId, ComponentName name) {
2276         final Intent intent = new Intent();
2277         final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
2278         intent.setComponent(name);
2279         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2280         try {
2281             mContext.startActivityAsUser(intent, bundle, UserHandle.of(mCurrentUserId));
2282         } catch (ActivityNotFoundException ignore) {
2283             // ignore the exception
2284         }
2285     }
2286 
launchAccessibilitySubSettings(int displayId, ComponentName name)2287     private void launchAccessibilitySubSettings(int displayId, ComponentName name) {
2288         final Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_DETAILS_SETTINGS);
2289         final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
2290         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
2291         intent.putExtra(Intent.EXTRA_COMPONENT_NAME, name.flattenToString());
2292         try {
2293             mContext.startActivityAsUser(intent, bundle, UserHandle.of(mCurrentUserId));
2294         } catch (ActivityNotFoundException ignore) {
2295             // ignore the exception
2296         }
2297     }
2298 
launchHearingDevicesDialog()2299     private void launchHearingDevicesDialog() {
2300         final Intent intent = new Intent(ACTION_LAUNCH_HEARING_DEVICES_DIALOG);
2301         intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
2302         intent.setPackage(
2303                 mContext.getString(com.android.internal.R.string.config_systemUi));
2304         mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
2305     }
2306 
notifyAccessibilityButtonVisibilityChangedLocked(boolean available)2307     private void notifyAccessibilityButtonVisibilityChangedLocked(boolean available) {
2308         final AccessibilityUserState state = getCurrentUserStateLocked();
2309         mIsAccessibilityButtonShown = available;
2310         for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
2311             final AccessibilityServiceConnection clientConnection = state.mBoundServices.get(i);
2312             if (clientConnection.mRequestAccessibilityButton) {
2313                 clientConnection.notifyAccessibilityButtonAvailabilityChangedLocked(
2314                         clientConnection.isAccessibilityButtonAvailableLocked(state));
2315             }
2316         }
2317     }
2318 
2319     /**
2320      * Finds packages that provide AccessibilityService interfaces, and parses
2321      * their metadata XML to build up {@link AccessibilityServiceInfo} objects.
2322      *
2323      * <p>
2324      * <strong>Note:</strong> XML parsing is a resource-heavy operation that may
2325      * stall, so this method should not be called while holding a lock.
2326      * </p>
2327      */
parseAccessibilityServiceInfos(int userId)2328     private List<AccessibilityServiceInfo> parseAccessibilityServiceInfos(int userId) {
2329         List<AccessibilityServiceInfo> result = new ArrayList<>();
2330 
2331         int flags = PackageManager.GET_SERVICES
2332                 | PackageManager.GET_META_DATA
2333                 | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
2334                 | PackageManager.MATCH_DIRECT_BOOT_AWARE
2335                 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
2336 
2337         synchronized (mLock) {
2338             if (getUserStateLocked(userId).getBindInstantServiceAllowedLocked()) {
2339                 flags |= PackageManager.MATCH_INSTANT;
2340             }
2341         }
2342 
2343         List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser(
2344                 new Intent(AccessibilityService.SERVICE_INTERFACE), flags, userId);
2345 
2346         for (int i = 0, count = installedServices.size(); i < count; i++) {
2347             ResolveInfo resolveInfo = installedServices.get(i);
2348             ServiceInfo serviceInfo = resolveInfo.serviceInfo;
2349 
2350             if (!mSecurityPolicy.canRegisterService(serviceInfo)) {
2351                 continue;
2352             }
2353 
2354             AccessibilityServiceInfo accessibilityServiceInfo;
2355             try {
2356                 accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext);
2357             } catch (XmlPullParserException | IOException xppe) {
2358                 Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe);
2359                 continue;
2360             }
2361             if (!accessibilityServiceInfo.isWithinParcelableSize()) {
2362                 Slog.e(LOG_TAG, "Skipping service "
2363                         + accessibilityServiceInfo.getResolveInfo().getComponentInfo()
2364                         + " because service info size is larger than safe parcelable limits.");
2365                 continue;
2366             }
2367             result.add(accessibilityServiceInfo);
2368         }
2369         return result;
2370     }
2371 
readInstalledAccessibilityServiceLocked(AccessibilityUserState userState, @Nullable List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos)2372     private boolean readInstalledAccessibilityServiceLocked(AccessibilityUserState userState,
2373             @Nullable List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos) {
2374         for (int i = 0, count = parsedAccessibilityServiceInfos.size(); i < count; i++) {
2375             AccessibilityServiceInfo accessibilityServiceInfo =
2376                     parsedAccessibilityServiceInfos.get(i);
2377             if (userState.mCrashedServices.contains(accessibilityServiceInfo.getComponentName())) {
2378                 // Restore the crashed attribute.
2379                 accessibilityServiceInfo.crashed = true;
2380             }
2381         }
2382 
2383         if (!parsedAccessibilityServiceInfos.equals(userState.mInstalledServices)) {
2384             userState.mInstalledServices.clear();
2385             userState.mInstalledServices.addAll(parsedAccessibilityServiceInfos);
2386             userState.updateTileServiceMapForAccessibilityServiceLocked();
2387             return true;
2388         }
2389         return false;
2390     }
2391 
2392     /**
2393      * Returns the {@link AccessibilityShortcutInfo}s of the installed
2394      * accessibility shortcut targets for the given user.
2395      *
2396      * <p>
2397      * <strong>Note:</strong> XML parsing is a resource-heavy operation that may
2398      * stall, so this method should not be called while holding a lock.
2399      * </p>
2400      */
parseAccessibilityShortcutInfos(int userId)2401     private List<AccessibilityShortcutInfo> parseAccessibilityShortcutInfos(int userId) {
2402         // TODO: b/297279151 - This should be implemented here, not by AccessibilityManager.
2403         return AccessibilityManager.getInstance(mContext)
2404                 .getInstalledAccessibilityShortcutListAsUser(mContext, userId);
2405     }
2406 
readInstalledAccessibilityShortcutLocked(AccessibilityUserState userState, List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos)2407     private boolean readInstalledAccessibilityShortcutLocked(AccessibilityUserState userState,
2408             List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos) {
2409         if (!parsedAccessibilityShortcutInfos.equals(userState.mInstalledShortcuts)) {
2410             userState.mInstalledShortcuts.clear();
2411             userState.mInstalledShortcuts.addAll(parsedAccessibilityShortcutInfos);
2412             userState.updateTileServiceMapForAccessibilityActivityLocked();
2413             return true;
2414         }
2415         return false;
2416     }
2417 
readEnabledAccessibilityServicesLocked(AccessibilityUserState userState)2418     private boolean readEnabledAccessibilityServicesLocked(AccessibilityUserState userState) {
2419         mTempComponentNameSet.clear();
2420         readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
2421                 userState.mUserId, mTempComponentNameSet);
2422         if (!mTempComponentNameSet.equals(userState.mEnabledServices)) {
2423             userState.mEnabledServices.clear();
2424             userState.mEnabledServices.addAll(mTempComponentNameSet);
2425             mTempComponentNameSet.clear();
2426             return true;
2427         }
2428         mTempComponentNameSet.clear();
2429         return false;
2430     }
2431 
readTouchExplorationGrantedAccessibilityServicesLocked( AccessibilityUserState userState)2432     private boolean readTouchExplorationGrantedAccessibilityServicesLocked(
2433             AccessibilityUserState userState) {
2434         mTempComponentNameSet.clear();
2435         readComponentNamesFromSettingLocked(
2436                 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
2437                 userState.mUserId, mTempComponentNameSet);
2438         if (!mTempComponentNameSet.equals(userState.mTouchExplorationGrantedServices)) {
2439             userState.mTouchExplorationGrantedServices.clear();
2440             userState.mTouchExplorationGrantedServices.addAll(mTempComponentNameSet);
2441             mTempComponentNameSet.clear();
2442             return true;
2443         }
2444         mTempComponentNameSet.clear();
2445         return false;
2446     }
2447 
2448     /**
2449      * Performs {@link AccessibilityService}s delayed notification. The delay is configurable
2450      * and denotes the period after the last event before notifying the service.
2451      *
2452      * @param event The event.
2453      * @param isDefault True to notify default listeners, not default services.
2454      */
notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event, boolean isDefault)2455     private void notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event,
2456             boolean isDefault) {
2457         try {
2458             AccessibilityUserState state = getCurrentUserStateLocked();
2459             for (int i = 0, count = state.mBoundServices.size(); i < count; i++) {
2460                 AccessibilityServiceConnection service = state.mBoundServices.get(i);
2461 
2462                 if (service.mIsDefault == isDefault) {
2463                     service.notifyAccessibilityEvent(event);
2464                 }
2465             }
2466         } catch (IndexOutOfBoundsException oobe) {
2467             // An out of bounds exception can happen if services are going away
2468             // as the for loop is running. If that happens, just bail because
2469             // there are no more services to notify.
2470         }
2471     }
2472 
updateRelevantEventsLocked(AccessibilityUserState userState)2473     private void updateRelevantEventsLocked(AccessibilityUserState userState) {
2474         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_SERVICE_CLIENT)) {
2475             mTraceManager.logTrace(LOG_TAG + ".updateRelevantEventsLocked",
2476                     FLAGS_ACCESSIBILITY_SERVICE_CLIENT, "userState=" + userState);
2477         }
2478         mMainHandler.post(() -> {
2479             broadcastToClients(userState, ignoreRemoteException(client -> {
2480                 int relevantEventTypes;
2481                 synchronized (mLock) {
2482                     relevantEventTypes = computeRelevantEventTypesLocked(userState, client);
2483                     if (!mProxyManager.isProxyedDeviceId(client.mDeviceId)) {
2484                         if (client.mLastSentRelevantEventTypes != relevantEventTypes) {
2485                             client.mLastSentRelevantEventTypes = relevantEventTypes;
2486                             client.mCallback.setRelevantEventTypes(relevantEventTypes);
2487                         }
2488                     }
2489                 }
2490             }));
2491         });
2492     }
2493 
computeRelevantEventTypesLocked(AccessibilityUserState userState, Client client)2494     private int computeRelevantEventTypesLocked(AccessibilityUserState userState, Client client) {
2495         int relevantEventTypes = 0;
2496 
2497         int serviceCount = userState.mBoundServices.size();
2498         for (int i = 0; i < serviceCount; i++) {
2499             AccessibilityServiceConnection service = userState.mBoundServices.get(i);
2500             relevantEventTypes |= isClientInPackageAllowlist(service.getServiceInfo(), client)
2501                     ? service.getRelevantEventTypes()
2502                     : 0;
2503         }
2504 
2505         relevantEventTypes |= isClientInPackageAllowlist(
2506                 mUiAutomationManager.getServiceInfo(), client)
2507                 ? mUiAutomationManager.getRelevantEventTypes()
2508                 : 0;
2509         return relevantEventTypes;
2510     }
2511 
updateMagnificationModeChangeSettingsLocked(AccessibilityUserState userState, int displayId)2512     private void updateMagnificationModeChangeSettingsLocked(AccessibilityUserState userState,
2513             int displayId) {
2514         if (userState.mUserId != mCurrentUserId) {
2515             return;
2516         }
2517         // New mode is invalid, so ignore and restore it.
2518         if (fallBackMagnificationModeSettingsLocked(userState, displayId)) {
2519             return;
2520         }
2521         mMagnificationController.transitionMagnificationModeLocked(
2522                 displayId, userState.getMagnificationModeLocked(displayId),
2523                 this::onMagnificationTransitionEndedLocked);
2524     }
2525 
2526     /**
2527      * Called when the magnification mode transition is completed. If the given display is default
2528      * display, we also need to fall back the mode in user settings.
2529      */
onMagnificationTransitionEndedLocked(int displayId, boolean success)2530     void onMagnificationTransitionEndedLocked(int displayId, boolean success) {
2531         final AccessibilityUserState userState = getCurrentUserStateLocked();
2532         final int previousMode = userState.getMagnificationModeLocked(displayId)
2533                 ^ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
2534         if (!success && previousMode != 0) {
2535             userState.setMagnificationModeLocked(displayId, previousMode);
2536             if (displayId == Display.DEFAULT_DISPLAY) {
2537                 persistMagnificationModeSettingsLocked(previousMode);
2538             }
2539         } else {
2540             mMainHandler.sendMessage(obtainMessage(
2541                     AccessibilityManagerService::notifyRefreshMagnificationModeToInputFilter,
2542                     this, displayId));
2543         }
2544     }
2545 
notifyRefreshMagnificationModeToInputFilter(int displayId)2546     private void notifyRefreshMagnificationModeToInputFilter(int displayId) {
2547         synchronized (mLock) {
2548             if (!mHasInputFilter) {
2549                 return;
2550             }
2551             final ArrayList<Display> displays = getValidDisplayList();
2552             for (int i = 0; i < displays.size(); i++) {
2553                 final Display display = displays.get(i);
2554                 if (display != null && display.getDisplayId() == displayId) {
2555                     mInputFilter.refreshMagnificationMode(display);
2556                     return;
2557                 }
2558             }
2559         }
2560     }
2561 
isClientInPackageAllowlist( @ullable AccessibilityServiceInfo serviceInfo, Client client)2562     static boolean isClientInPackageAllowlist(
2563             @Nullable AccessibilityServiceInfo serviceInfo, Client client) {
2564         if (serviceInfo == null) return false;
2565 
2566         String[] clientPackages = client.mPackageNames;
2567         boolean result = ArrayUtils.isEmpty(serviceInfo.packageNames);
2568         if (!result && clientPackages != null) {
2569             for (String packageName : clientPackages) {
2570                 if (ArrayUtils.contains(serviceInfo.packageNames, packageName)) {
2571                     result = true;
2572                     break;
2573                 }
2574             }
2575         }
2576         if (!result) {
2577             if (DEBUG) {
2578                 Slog.d(LOG_TAG, "Dropping events: "
2579                         + Arrays.toString(clientPackages) + " -> "
2580                         + serviceInfo.getComponentName().flattenToShortString()
2581                         + " due to not being in package allowlist "
2582                         + Arrays.toString(serviceInfo.packageNames));
2583             }
2584         }
2585 
2586         return result;
2587     }
2588 
broadcastToClients( AccessibilityUserState userState, Consumer<Client> clientAction)2589     private void broadcastToClients(
2590             AccessibilityUserState userState, Consumer<Client> clientAction) {
2591         mGlobalClients.broadcastForEachCookie(clientAction);
2592         userState.mUserClients.broadcastForEachCookie(clientAction);
2593     }
2594 
2595     /**
2596      * Populates a set with the {@link ComponentName}s stored in a colon
2597      * separated value setting for a given user.
2598      *
2599      * @param settingName The setting to parse.
2600      * @param userId The user id.
2601      * @param outComponentNames The output component names.
2602      */
2603     @VisibleForTesting
readComponentNamesFromSettingLocked(String settingName, int userId, Set<ComponentName> outComponentNames)2604     void readComponentNamesFromSettingLocked(String settingName, int userId,
2605             Set<ComponentName> outComponentNames) {
2606         readColonDelimitedSettingToSet(settingName, userId,
2607                 str -> ComponentName.unflattenFromString(str), outComponentNames);
2608     }
2609 
2610     /**
2611      * Populates a set with the {@link ComponentName}s contained in a colon-delimited string.
2612      *
2613      * @param names The colon-delimited string to parse.
2614      * @param outComponentNames The set of component names to be populated based on
2615      *    the contents of the <code>names</code> string.
2616      * @param doMerge If true, the parsed component names will be merged into the output
2617      *    set, rather than replacing the set's existing contents entirely.
2618      */
readComponentNamesFromStringLocked(String names, Set<ComponentName> outComponentNames, boolean doMerge)2619     private void readComponentNamesFromStringLocked(String names,
2620             Set<ComponentName> outComponentNames,
2621             boolean doMerge) {
2622         readColonDelimitedStringToSet(names, str -> ComponentName.unflattenFromString(str),
2623                 outComponentNames, doMerge);
2624     }
2625 
2626     @Override
persistComponentNamesToSettingLocked(String settingName, Set<ComponentName> componentNames, int userId)2627     public void persistComponentNamesToSettingLocked(String settingName,
2628             Set<ComponentName> componentNames, int userId) {
2629         persistColonDelimitedSetToSettingLocked(settingName, userId, componentNames,
2630                 componentName -> componentName.flattenToShortString());
2631     }
2632 
2633     /**
2634      * Reads a colon delimited setting,
2635      * passes the values through a function,
2636      * then stores the values in a provided set.
2637      *
2638      * @param settingName Name of setting.
2639      * @param userId user id corresponding to setting.
2640      * @param toItem function mapping values to the output set.
2641      * @param outSet output set to write to.
2642      * @param <T> type of output set.
2643      */
2644     @VisibleForTesting
readColonDelimitedSettingToSet(String settingName, int userId, Function<String, T> toItem, Set<T> outSet)2645     <T> void readColonDelimitedSettingToSet(String settingName, int userId,
2646             Function<String, T> toItem, Set<T> outSet) {
2647         final String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
2648                 settingName, userId);
2649         readColonDelimitedStringToSet(settingValue, toItem, outSet, false);
2650     }
2651 
readColonDelimitedStringToSet(String names, Function<String, T> toItem, Set<T> outSet, boolean doMerge)2652     private <T> void readColonDelimitedStringToSet(String names, Function<String, T> toItem,
2653             Set<T> outSet, boolean doMerge) {
2654         if (!doMerge) {
2655             outSet.clear();
2656         }
2657         if (!TextUtils.isEmpty(names)) {
2658             final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
2659             splitter.setString(names);
2660             while (splitter.hasNext()) {
2661                 final String str = splitter.next();
2662                 if (TextUtils.isEmpty(str)) {
2663                     continue;
2664                 }
2665                 final T item = toItem.apply(str);
2666                 if (item != null) {
2667                     outSet.add(item);
2668                 }
2669             }
2670         }
2671     }
2672 
persistColonDelimitedSetToSettingLocked(String settingName, int userId, Set<T> set, Function<T, String> toString)2673     private <T> void persistColonDelimitedSetToSettingLocked(String settingName, int userId,
2674             Set<T> set, Function<T, String> toString) {
2675         persistColonDelimitedSetToSettingLocked(settingName, userId, set,
2676                 toString, /* defaultEmptyString= */ null);
2677     }
2678 
persistColonDelimitedSetToSettingLocked(String settingName, int userId, Set<T> set, Function<T, String> toString, String defaultEmptyString)2679     private <T> void persistColonDelimitedSetToSettingLocked(String settingName, int userId,
2680             Set<T> set, Function<T, String> toString, String defaultEmptyString) {
2681         final StringBuilder builder = new StringBuilder();
2682         for (T item : set) {
2683             final String str = (item != null ? toString.apply(item) : null);
2684             if (TextUtils.isEmpty(str)) {
2685                 continue;
2686             }
2687             if (builder.length() > 0) {
2688                 builder.append(COMPONENT_NAME_SEPARATOR);
2689             }
2690             builder.append(str);
2691         }
2692         final String builderValue = builder.toString();
2693         final String settingValue = TextUtils.isEmpty(builderValue)
2694                 ? defaultEmptyString : builderValue;
2695         if (android.view.accessibility.Flags.restoreA11yShortcutTargetService()) {
2696             final String currentValue = Settings.Secure.getStringForUser(
2697                     mContext.getContentResolver(), settingName, userId);
2698             if (Objects.equals(settingValue, currentValue)) {
2699                 // This logic exists to fix a bug where AccessibilityManagerService was writing
2700                 // `null` to the ACCESSIBILITY_SHORTCUT_TARGET_SERVICE setting during early boot
2701                 // during setup, due to a race condition in package scanning making A11yMS think
2702                 // that the default service was not installed.
2703                 //
2704                 // Writing `null` was implicitly causing that Setting to have the default
2705                 // `DEFAULT_OVERRIDEABLE_BY_RESTORE` property, which was preventing B&R for that
2706                 // Setting altogether.
2707                 //
2708                 // The "quick fix" here is to not write `null` if the existing value is already
2709                 // `null`. The ideal fix would be use the Settings.Secure#putStringForUser overload
2710                 // that allows override-by-restore, but the full repercussions of using that here
2711                 // have not yet been evaluated.
2712                 // TODO: b/333457719 - Evaluate and fix AccessibilityManagerService's usage of
2713                 //  "overridable by restore" when writing secure settings.
2714                 return;
2715             }
2716         }
2717         final long identity = Binder.clearCallingIdentity();
2718         try {
2719             Settings.Secure.putStringForUser(mContext.getContentResolver(),
2720                     settingName, settingValue, userId);
2721         } finally {
2722             Binder.restoreCallingIdentity(identity);
2723         }
2724     }
2725 
persistIntToSetting(int userId, String settingName, int settingValue)2726     private void persistIntToSetting(int userId, String settingName, int settingValue) {
2727         final long identity = Binder.clearCallingIdentity();
2728         try {
2729             Settings.Secure.putIntForUser(
2730                     mContext.getContentResolver(), settingName, settingValue, userId);
2731         } finally {
2732             Binder.restoreCallingIdentity(identity);
2733         }
2734     }
2735 
updateServicesLocked(AccessibilityUserState userState)2736     private void updateServicesLocked(AccessibilityUserState userState) {
2737         Map<ComponentName, AccessibilityServiceConnection> componentNameToServiceMap =
2738                 userState.mComponentNameToServiceMap;
2739         boolean isUnlockingOrUnlocked = mUmi.isUserUnlockingOrUnlocked(userState.mUserId);
2740 
2741         // Store the list of installed services.
2742         mTempComponentNameSet.clear();
2743         for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
2744             AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i);
2745             ComponentName componentName = ComponentName.unflattenFromString(
2746                     installedService.getId());
2747             mTempComponentNameSet.add(componentName);
2748 
2749             AccessibilityServiceConnection service = componentNameToServiceMap.get(componentName);
2750 
2751             // Ignore non-encryption-aware services until user is unlocked
2752             if (!isUnlockingOrUnlocked && !installedService.isDirectBootAware()) {
2753                 Slog.d(LOG_TAG, "Ignoring non-encryption-aware service " + componentName);
2754                 continue;
2755             }
2756 
2757             // Skip the component since it may be in process or crashed.
2758             if (userState.getBindingServicesLocked().contains(componentName)
2759                     || userState.getCrashedServicesLocked().contains(componentName)) {
2760                 continue;
2761             }
2762             if (userState.mEnabledServices.contains(componentName)
2763                     && !mUiAutomationManager.suppressingAccessibilityServicesLocked()) {
2764                 // Skip the enabling service disallowed by device admin policy.
2765                 if (!isAccessibilityTargetAllowed(componentName.getPackageName(),
2766                         installedService.getResolveInfo().serviceInfo.applicationInfo.uid,
2767                         userState.mUserId)) {
2768                     Slog.d(LOG_TAG, "Skipping enabling service disallowed by device admin policy: "
2769                             + componentName);
2770                     disableAccessibilityServiceLocked(componentName, userState.mUserId);
2771                     continue;
2772                 }
2773                 if (service == null) {
2774                     service = new AccessibilityServiceConnection(userState, mContext, componentName,
2775                             installedService, sIdCounter++, mMainHandler, mLock, mSecurityPolicy,
2776                             this, getTraceManager(), mWindowManagerService,
2777                             getSystemActionPerformer(), mA11yWindowManager,
2778                             mActivityTaskManagerService);
2779                 } else if (userState.mBoundServices.contains(service)) {
2780                     continue;
2781                 }
2782                 service.bindLocked();
2783             } else {
2784                 if (service != null) {
2785                     service.unbindLocked();
2786                     removeShortcutTargetForUnboundServiceLocked(userState, service);
2787                 }
2788             }
2789         }
2790 
2791         final int count = userState.mBoundServices.size();
2792         mTempIntArray.clear();
2793         for (int i = 0; i < count; i++) {
2794             final ResolveInfo resolveInfo =
2795                     userState.mBoundServices.get(i).mAccessibilityServiceInfo.getResolveInfo();
2796             if (resolveInfo != null) {
2797                 mTempIntArray.add(resolveInfo.serviceInfo.applicationInfo.uid);
2798             }
2799         }
2800         // Calling out with lock held, but to lower-level services
2801         final AudioManagerInternal audioManager =
2802                 LocalServices.getService(AudioManagerInternal.class);
2803         if (audioManager != null) {
2804             audioManager.setAccessibilityServiceUids(mTempIntArray);
2805         }
2806         mActivityTaskManagerService.setAccessibilityServiceUids(mTempIntArray);
2807 
2808         // If any services have been removed, remove them from the enabled list and the touch
2809         // exploration granted list.
2810         boolean anyServiceRemoved =
2811                 userState.mEnabledServices.removeIf((comp) -> !mTempComponentNameSet.contains(comp))
2812                         || userState.mTouchExplorationGrantedServices.removeIf(
2813                                 (comp) -> !mTempComponentNameSet.contains(comp));
2814         if (anyServiceRemoved) {
2815             // Update the enabled services setting.
2816             persistComponentNamesToSettingLocked(
2817                     Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
2818                     userState.mEnabledServices,
2819                     userState.mUserId);
2820             // Update the touch exploration granted services setting.
2821             persistComponentNamesToSettingLocked(
2822                     Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
2823                     userState.mTouchExplorationGrantedServices,
2824                     userState.mUserId);
2825         }
2826         updateAccessibilityEnabledSettingLocked(userState);
2827     }
2828 
scheduleUpdateClientsIfNeededLocked(AccessibilityUserState userState)2829     void scheduleUpdateClientsIfNeededLocked(AccessibilityUserState userState) {
2830         scheduleUpdateClientsIfNeededLocked(userState, false);
2831     }
2832 
scheduleUpdateClientsIfNeededLocked(AccessibilityUserState userState, boolean forceUpdate)2833     void scheduleUpdateClientsIfNeededLocked(AccessibilityUserState userState,
2834             boolean forceUpdate) {
2835         final int clientState = getClientStateLocked(userState);
2836         if (((userState.getLastSentClientStateLocked() != clientState || forceUpdate))
2837                 && (mGlobalClients.getRegisteredCallbackCount() > 0
2838                 || userState.mUserClients.getRegisteredCallbackCount() > 0)) {
2839             userState.setLastSentClientStateLocked(clientState);
2840             mMainHandler.sendMessage(obtainMessage(
2841                     AccessibilityManagerService::sendStateToAllClients,
2842                     this, clientState,
2843                     userState.mUserId));
2844         }
2845     }
2846 
sendStateToAllClients(int clientState, int userId)2847     private void sendStateToAllClients(int clientState, int userId) {
2848         sendStateToClients(clientState, mGlobalClients);
2849         sendStateToClients(clientState, userId);
2850     }
2851 
sendStateToClients(int clientState, int userId)2852     private void sendStateToClients(int clientState, int userId) {
2853         sendStateToClients(clientState, getUserState(userId).mUserClients);
2854     }
2855 
sendStateToClients(int clientState, RemoteCallbackList<IAccessibilityManagerClient> clients)2856     private void sendStateToClients(int clientState,
2857             RemoteCallbackList<IAccessibilityManagerClient> clients) {
2858         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER_CLIENT)) {
2859             mTraceManager.logTrace(LOG_TAG + ".sendStateToClients",
2860                     FLAGS_ACCESSIBILITY_MANAGER_CLIENT, "clientState=" + clientState);
2861         }
2862         clients.broadcastForEachCookie(ignoreRemoteException(
2863                 client -> {
2864                     Client managerClient = ((Client) client);
2865                     if (!mProxyManager.isProxyedDeviceId(managerClient.mDeviceId)) {
2866                         managerClient.mCallback.setState(clientState);
2867                     }
2868                 }));
2869     }
2870 
scheduleNotifyClientsOfServicesStateChangeLocked( AccessibilityUserState userState)2871     private void scheduleNotifyClientsOfServicesStateChangeLocked(
2872             AccessibilityUserState userState) {
2873         updateRecommendedUiTimeoutLocked(userState);
2874         mMainHandler.sendMessage(obtainMessage(
2875                 AccessibilityManagerService::sendServicesStateChanged,
2876                 this, userState.mUserClients, getRecommendedTimeoutMillisLocked(userState)));
2877     }
2878 
sendServicesStateChanged( RemoteCallbackList<IAccessibilityManagerClient> userClients, long uiTimeout)2879     private void sendServicesStateChanged(
2880             RemoteCallbackList<IAccessibilityManagerClient> userClients, long uiTimeout) {
2881         notifyClientsOfServicesStateChange(mGlobalClients, uiTimeout);
2882         notifyClientsOfServicesStateChange(userClients, uiTimeout);
2883     }
2884 
notifyClientsOfServicesStateChange( RemoteCallbackList<IAccessibilityManagerClient> clients, long uiTimeout)2885     private void notifyClientsOfServicesStateChange(
2886             RemoteCallbackList<IAccessibilityManagerClient> clients, long uiTimeout) {
2887         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER_CLIENT)) {
2888             mTraceManager.logTrace(LOG_TAG + ".notifyClientsOfServicesStateChange",
2889                     FLAGS_ACCESSIBILITY_MANAGER_CLIENT, "uiTimeout=" + uiTimeout);
2890         }
2891 
2892         clients.broadcastForEachCookie(ignoreRemoteException(
2893                 client -> {
2894                     Client managerClient = ((Client) client);
2895                     if (!mProxyManager.isProxyedDeviceId(managerClient.mDeviceId)) {
2896                         managerClient.mCallback.notifyServicesStateChanged(uiTimeout);
2897                     }
2898                 }));
2899     }
2900 
scheduleUpdateInputFilter(AccessibilityUserState userState)2901     private void scheduleUpdateInputFilter(AccessibilityUserState userState) {
2902         mMainHandler.sendMessage(obtainMessage(
2903                 AccessibilityManagerService::updateInputFilter, this, userState));
2904     }
2905 
scheduleUpdateFingerprintGestureHandling(AccessibilityUserState userState)2906     private void scheduleUpdateFingerprintGestureHandling(AccessibilityUserState userState) {
2907         mMainHandler.sendMessage(obtainMessage(
2908                 AccessibilityManagerService::updateFingerprintGestureHandling,
2909                 this, userState));
2910     }
2911 
updateInputFilter(AccessibilityUserState userState)2912     private void updateInputFilter(AccessibilityUserState userState) {
2913         if (mUiAutomationManager.suppressingAccessibilityServicesLocked()) return;
2914 
2915         boolean setInputFilter = false;
2916         AccessibilityInputFilter inputFilter = null;
2917         synchronized (mLock) {
2918             int flags = 0;
2919             if (userState.isMagnificationSingleFingerTripleTapEnabledLocked()) {
2920                 flags |= AccessibilityInputFilter
2921                         .FLAG_FEATURE_MAGNIFICATION_SINGLE_FINGER_TRIPLE_TAP;
2922             }
2923             if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) {
2924                 if (userState.isMagnificationTwoFingerTripleTapEnabledLocked()) {
2925                     flags |= AccessibilityInputFilter
2926                             .FLAG_FEATURE_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP;
2927                 }
2928             }
2929             if (userState.isShortcutMagnificationEnabledLocked()) {
2930                 flags |= AccessibilityInputFilter.FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER;
2931             }
2932             if (userHasMagnificationServicesLocked(userState)) {
2933                 flags |= AccessibilityInputFilter.FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER;
2934             }
2935             // Touch exploration without accessibility makes no sense.
2936             if (userState.isHandlingAccessibilityEventsLocked()
2937                     && userState.isTouchExplorationEnabledLocked()) {
2938                 flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
2939                 if (userState.isServiceHandlesDoubleTapEnabledLocked()) {
2940                     flags |= AccessibilityInputFilter.FLAG_SERVICE_HANDLES_DOUBLE_TAP;
2941                 }
2942                 if (userState.isMultiFingerGesturesEnabledLocked()) {
2943                     flags |= AccessibilityInputFilter.FLAG_REQUEST_MULTI_FINGER_GESTURES;
2944                 }
2945                 if (userState.isTwoFingerPassthroughEnabledLocked()) {
2946                     flags |= AccessibilityInputFilter.FLAG_REQUEST_2_FINGER_PASSTHROUGH;
2947                 }
2948             }
2949             if (userState.isFilterKeyEventsEnabledLocked()) {
2950                 flags |= AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS;
2951             }
2952             if (userState.isSendMotionEventsEnabled()) {
2953                 flags |= AccessibilityInputFilter.FLAG_SEND_MOTION_EVENTS;
2954             }
2955             if (userState.isAutoclickEnabledLocked()) {
2956                 flags |= AccessibilityInputFilter.FLAG_FEATURE_AUTOCLICK;
2957             }
2958             if (userState.isPerformGesturesEnabledLocked()) {
2959                 flags |= AccessibilityInputFilter.FLAG_FEATURE_INJECT_MOTION_EVENTS;
2960             }
2961             int combinedGenericMotionEventSources = 0;
2962             int combinedMotionEventObservedSources = 0;
2963             for (AccessibilityServiceConnection connection : userState.mBoundServices) {
2964                 combinedGenericMotionEventSources |= connection.mGenericMotionEventSources;
2965                 combinedMotionEventObservedSources |= connection.mObservedMotionEventSources;
2966             }
2967             if (combinedGenericMotionEventSources != 0) {
2968                 flags |= AccessibilityInputFilter.FLAG_FEATURE_INTERCEPT_GENERIC_MOTION_EVENTS;
2969             }
2970             if (flags != 0) {
2971                 if (!mHasInputFilter) {
2972                     mHasInputFilter = true;
2973                     if (mInputFilter == null) {
2974                         mInputFilter =
2975                                 new AccessibilityInputFilter(
2976                                         mContext, AccessibilityManagerService.this);
2977                     }
2978                     inputFilter = mInputFilter;
2979                     setInputFilter = true;
2980                 }
2981                 mInputFilter.setUserAndEnabledFeatures(userState.mUserId, flags);
2982                 mInputFilter.setCombinedGenericMotionEventSources(
2983                         combinedGenericMotionEventSources);
2984                 mInputFilter.setCombinedMotionEventObservedSources(
2985                         combinedMotionEventObservedSources);
2986             } else {
2987                 if (mHasInputFilter) {
2988                     mHasInputFilter = false;
2989                     mInputFilter.setUserAndEnabledFeatures(userState.mUserId, 0);
2990                     mInputFilter.resetServiceDetectsGestures();
2991                     if (userState.isTouchExplorationEnabledLocked()) {
2992                         //  Service gesture detection is turned on and off on a per-display
2993                         // basis.
2994                         final ArrayList<Display> displays = getValidDisplayList();
2995                         for (Display display : displays) {
2996                             int displayId = display.getDisplayId();
2997                             boolean mode = userState.isServiceDetectsGesturesEnabled(displayId);
2998                             mInputFilter.setServiceDetectsGesturesEnabled(displayId, mode);
2999                         }
3000                     }
3001                     inputFilter = null;
3002                     setInputFilter = true;
3003                 }
3004             }
3005         }
3006         if (setInputFilter) {
3007             if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL
3008                     | FLAGS_INPUT_FILTER)) {
3009                 mTraceManager.logTrace("WindowManagerInternal.setInputFilter",
3010                         FLAGS_WINDOW_MANAGER_INTERNAL | FLAGS_INPUT_FILTER,
3011                         "inputFilter=" + inputFilter);
3012             }
3013             mWindowManagerService.setInputFilter(inputFilter);
3014             mProxyManager.setAccessibilityInputFilter(inputFilter);
3015         }
3016     }
3017 
showEnableTouchExplorationDialog(final AccessibilityServiceConnection service)3018     private void showEnableTouchExplorationDialog(final AccessibilityServiceConnection service) {
3019         synchronized (mLock) {
3020             String label = service.getServiceInfo().getResolveInfo()
3021                     .loadLabel(mContext.getPackageManager()).toString();
3022 
3023             final AccessibilityUserState userState = getCurrentUserStateLocked();
3024             if (userState.isTouchExplorationEnabledLocked()) {
3025                 return;
3026             }
3027             if (mEnableTouchExplorationDialog != null
3028                     && mEnableTouchExplorationDialog.isShowing()) {
3029                 return;
3030             }
3031             mEnableTouchExplorationDialog = new AlertDialog.Builder(mContext)
3032                 .setIconAttribute(android.R.attr.alertDialogIcon)
3033                 .setPositiveButton(android.R.string.ok, new OnClickListener() {
3034                     @Override
3035                     public void onClick(DialogInterface dialog, int which) {
3036                         // The user allowed the service to toggle touch exploration.
3037                         userState.mTouchExplorationGrantedServices.add(service.mComponentName);
3038                         persistComponentNamesToSettingLocked(
3039                                 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
3040                                 userState.mTouchExplorationGrantedServices, userState.mUserId);
3041                         // Enable touch exploration.
3042                         userState.setTouchExplorationEnabledLocked(true);
3043                         final long identity = Binder.clearCallingIdentity();
3044                         try {
3045                             Settings.Secure.putIntForUser(mContext.getContentResolver(),
3046                                     Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1,
3047                                     userState.mUserId);
3048                         } finally {
3049                             Binder.restoreCallingIdentity(identity);
3050                         }
3051                         onUserStateChangedLocked(userState);
3052                     }
3053                 })
3054                 .setNegativeButton(android.R.string.cancel, new OnClickListener() {
3055                     @Override
3056                     public void onClick(DialogInterface dialog, int which) {
3057                         dialog.dismiss();
3058                     }
3059                 })
3060                 .setTitle(R.string.enable_explore_by_touch_warning_title)
3061                 .setMessage(mContext.getString(
3062                         R.string.enable_explore_by_touch_warning_message, label))
3063                 .create();
3064              mEnableTouchExplorationDialog.getWindow().setType(
3065                      WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
3066              mEnableTouchExplorationDialog.getWindow().getAttributes().privateFlags
3067                      |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
3068              mEnableTouchExplorationDialog.setCanceledOnTouchOutside(true);
3069              mEnableTouchExplorationDialog.show();
3070         }
3071     }
3072 
onUserVisibilityChanged(@serIdInt int userId, boolean visible)3073     private void onUserVisibilityChanged(@UserIdInt int userId, boolean visible) {
3074         if (DEBUG) {
3075             Slogf.d(LOG_TAG, "onUserVisibilityChanged(): %d => %b", userId, visible);
3076         }
3077         synchronized (mLock) {
3078             if (visible) {
3079                 mVisibleBgUserIds.put(userId, visible);
3080             } else {
3081                 mVisibleBgUserIds.delete(userId);
3082             }
3083         }
3084     }
3085 
3086     /**
3087      * Called when any property of the user state has changed.
3088      *
3089      * @param userState the new user state
3090      */
onUserStateChangedLocked(AccessibilityUserState userState)3091     private void onUserStateChangedLocked(AccessibilityUserState userState) {
3092         onUserStateChangedLocked(userState, false);
3093     }
3094 
3095     /**
3096      * Called when any property of the user state has changed.
3097      *
3098      * @param userState the new user state
3099      * @param forceUpdate whether to force an update of the app Clients.
3100      */
onUserStateChangedLocked(AccessibilityUserState userState, boolean forceUpdate)3101     private void onUserStateChangedLocked(AccessibilityUserState userState, boolean forceUpdate) {
3102         if (DEBUG) {
3103             Slog.v(LOG_TAG, "onUserStateChangedLocked for user " + userState.mUserId + " with "
3104                     + "forceUpdate: " + forceUpdate);
3105         }
3106         // TODO: Remove this hack
3107         mInitialized = true;
3108         updateLegacyCapabilitiesLocked(userState);
3109         updateServicesLocked(userState);
3110         updateWindowsForAccessibilityCallbackLocked(userState);
3111         updateFilterKeyEventsLocked(userState);
3112         updateTouchExplorationLocked(userState);
3113         updatePerformGesturesLocked(userState);
3114         updateMagnificationLocked(userState);
3115         scheduleUpdateFingerprintGestureHandling(userState);
3116         scheduleUpdateInputFilter(userState);
3117         updateRelevantEventsLocked(userState);
3118         scheduleUpdateClientsIfNeededLocked(userState, forceUpdate);
3119         updateAccessibilityShortcutKeyTargetsLocked(userState);
3120         updateAccessibilityButtonTargetsLocked(userState);
3121         updateAccessibilityQsTargetsLocked(userState);
3122         // Update the capabilities before the mode because we will check the current mode is
3123         // invalid or not..
3124         updateMagnificationCapabilitiesSettingsChangeLocked(userState);
3125         updateMagnificationModeChangeSettingsForAllDisplaysLocked(userState);
3126         updateFocusAppearanceDataLocked(userState);
3127     }
3128 
updateMagnificationModeChangeSettingsForAllDisplaysLocked( AccessibilityUserState userState)3129     private void updateMagnificationModeChangeSettingsForAllDisplaysLocked(
3130             AccessibilityUserState userState) {
3131         final ArrayList<Display> displays = getValidDisplayList();
3132         for (int i = 0; i < displays.size(); i++) {
3133             final int displayId = displays.get(i).getDisplayId();
3134             updateMagnificationModeChangeSettingsLocked(userState, displayId);
3135         }
3136     }
3137 
updateWindowsForAccessibilityCallbackLocked(AccessibilityUserState userState)3138     private void updateWindowsForAccessibilityCallbackLocked(AccessibilityUserState userState) {
3139         // We observe windows for accessibility only if there is at least
3140         // one bound service that can retrieve window content that specified
3141         // it is interested in accessing such windows. For services that are
3142         // binding we do an update pass after each bind event, so we run this
3143         // code and register the callback if needed.
3144 
3145         boolean observingWindows = mUiAutomationManager.canRetrieveInteractiveWindowsLocked()
3146                 || mProxyManager.canRetrieveInteractiveWindowsLocked();
3147         List<AccessibilityServiceConnection> boundServices = userState.mBoundServices;
3148         final int boundServiceCount = boundServices.size();
3149         for (int i = 0; !observingWindows && (i < boundServiceCount); i++) {
3150             AccessibilityServiceConnection boundService = boundServices.get(i);
3151             if (boundService.canRetrieveInteractiveWindowsLocked()) {
3152                 userState.setAccessibilityFocusOnlyInActiveWindow(false);
3153                 observingWindows = true;
3154             }
3155         }
3156         userState.setAccessibilityFocusOnlyInActiveWindow(true);
3157 
3158         // Gets all valid displays and start tracking windows of each display if there is at least
3159         // one bound service that can retrieve window content.
3160         final ArrayList<Display> displays = getValidDisplayList();
3161         for (int i = 0; i < displays.size(); i++) {
3162             final Display display = displays.get(i);
3163             if (display != null) {
3164                 if (observingWindows) {
3165                     mA11yWindowManager.startTrackingWindows(display.getDisplayId(),
3166                             mProxyManager.isProxyedDisplay(display.getDisplayId()));
3167                 } else {
3168                     mA11yWindowManager.stopTrackingWindows(display.getDisplayId());
3169                 }
3170             }
3171         }
3172     }
3173 
updateLegacyCapabilitiesLocked(AccessibilityUserState userState)3174     private void updateLegacyCapabilitiesLocked(AccessibilityUserState userState) {
3175         // Up to JB-MR1 we had a allowlist with services that can enable touch
3176         // exploration. When a service is first started we show a dialog to the
3177         // use to get a permission to allowlist the service.
3178         final int installedServiceCount = userState.mInstalledServices.size();
3179         for (int i = 0; i < installedServiceCount; i++) {
3180             AccessibilityServiceInfo serviceInfo = userState.mInstalledServices.get(i);
3181             ResolveInfo resolveInfo = serviceInfo.getResolveInfo();
3182             if ((serviceInfo.getCapabilities()
3183                         & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) == 0
3184                     && resolveInfo.serviceInfo.applicationInfo.targetSdkVersion
3185                         <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
3186                 ComponentName componentName = new ComponentName(
3187                         resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
3188                 if (userState.mTouchExplorationGrantedServices.contains(componentName)) {
3189                     serviceInfo.setCapabilities(serviceInfo.getCapabilities()
3190                             | AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION);
3191                 }
3192             }
3193         }
3194     }
3195 
updatePerformGesturesLocked(AccessibilityUserState userState)3196     private void updatePerformGesturesLocked(AccessibilityUserState userState) {
3197         final int serviceCount = userState.mBoundServices.size();
3198         for (int i = 0; i < serviceCount; i++) {
3199             AccessibilityServiceConnection service = userState.mBoundServices.get(i);
3200             if ((service.getCapabilities()
3201                     & AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES) != 0) {
3202                 userState.setPerformGesturesEnabledLocked(true);
3203                 return;
3204             }
3205         }
3206         userState.setPerformGesturesEnabledLocked(false);
3207     }
3208 
updateFilterKeyEventsLocked(AccessibilityUserState userState)3209     private void updateFilterKeyEventsLocked(AccessibilityUserState userState) {
3210         final int serviceCount = userState.mBoundServices.size();
3211         for (int i = 0; i < serviceCount; i++) {
3212             AccessibilityServiceConnection service = userState.mBoundServices.get(i);
3213             if (service.mRequestFilterKeyEvents
3214                     && (service.getCapabilities()
3215                             & AccessibilityServiceInfo
3216                             .CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) != 0) {
3217                 userState.setFilterKeyEventsEnabledLocked(true);
3218                 return;
3219             }
3220         }
3221         userState.setFilterKeyEventsEnabledLocked(false);
3222     }
3223 
readConfigurationForUserStateLocked( AccessibilityUserState userState, List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos, List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos)3224     private boolean readConfigurationForUserStateLocked(
3225             AccessibilityUserState userState,
3226             List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos,
3227             List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos) {
3228         boolean somethingChanged = readInstalledAccessibilityServiceLocked(
3229                 userState, parsedAccessibilityServiceInfos);
3230         somethingChanged |= readInstalledAccessibilityShortcutLocked(
3231                 userState, parsedAccessibilityShortcutInfos);
3232         somethingChanged |= readEnabledAccessibilityServicesLocked(userState);
3233         somethingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState);
3234         somethingChanged |= readTouchExplorationEnabledSettingLocked(userState);
3235         somethingChanged |= readHighTextContrastEnabledSettingLocked(userState);
3236         somethingChanged |= readAudioDescriptionEnabledSettingLocked(userState);
3237         somethingChanged |= readMagnificationEnabledSettingsLocked(userState);
3238         somethingChanged |= readAutoclickEnabledSettingLocked(userState);
3239         somethingChanged |= readAccessibilityShortcutKeySettingLocked(userState);
3240         somethingChanged |= readAccessibilityQsTargetsLocked(userState);
3241         somethingChanged |= readAccessibilityButtonTargetsLocked(userState);
3242         somethingChanged |= readAccessibilityButtonTargetComponentLocked(userState);
3243         somethingChanged |= readUserRecommendedUiTimeoutSettingsLocked(userState);
3244         somethingChanged |= readMagnificationModeForDefaultDisplayLocked(userState);
3245         somethingChanged |= readMagnificationCapabilitiesLocked(userState);
3246         somethingChanged |= readMagnificationFollowTypingLocked(userState);
3247         somethingChanged |= readAlwaysOnMagnificationLocked(userState);
3248         return somethingChanged;
3249     }
3250 
updateAccessibilityEnabledSettingLocked(AccessibilityUserState userState)3251     private void updateAccessibilityEnabledSettingLocked(AccessibilityUserState userState) {
3252         final boolean isA11yEnabled = mUiAutomationManager.canIntrospect()
3253                 || userState.isHandlingAccessibilityEventsLocked();
3254         final long identity = Binder.clearCallingIdentity();
3255         try {
3256             Settings.Secure.putIntForUser(mContext.getContentResolver(),
3257                     Settings.Secure.ACCESSIBILITY_ENABLED,
3258                     (isA11yEnabled) ? 1 : 0,
3259                     userState.mUserId);
3260         } finally {
3261             Binder.restoreCallingIdentity(identity);
3262         }
3263     }
3264 
readTouchExplorationEnabledSettingLocked(AccessibilityUserState userState)3265     private boolean readTouchExplorationEnabledSettingLocked(AccessibilityUserState userState) {
3266         final boolean touchExplorationEnabled = Settings.Secure.getIntForUser(
3267                 mContext.getContentResolver(),
3268                 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId) == 1;
3269         if (touchExplorationEnabled != userState.isTouchExplorationEnabledLocked()) {
3270             userState.setTouchExplorationEnabledLocked(touchExplorationEnabled);
3271             return true;
3272         }
3273         return false;
3274     }
3275 
readMagnificationEnabledSettingsLocked(AccessibilityUserState userState)3276     private boolean readMagnificationEnabledSettingsLocked(AccessibilityUserState userState) {
3277         final boolean magnificationSingleFingerTripleTapEnabled = Settings.Secure.getIntForUser(
3278                 mContext.getContentResolver(),
3279                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
3280                 0, userState.mUserId) == 1;
3281         if ((magnificationSingleFingerTripleTapEnabled
3282                 != userState.isMagnificationSingleFingerTripleTapEnabledLocked())) {
3283             userState.setMagnificationSingleFingerTripleTapEnabledLocked(
3284                     magnificationSingleFingerTripleTapEnabled);
3285             return true;
3286         }
3287         return false;
3288     }
3289 
readMagnificationTwoFingerTripleTapSettingsLocked( AccessibilityUserState userState)3290     private boolean readMagnificationTwoFingerTripleTapSettingsLocked(
3291             AccessibilityUserState userState) {
3292         final boolean magnificationTwoFingerTripleTapEnabled = Settings.Secure.getIntForUser(
3293                 mContext.getContentResolver(),
3294                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
3295                 0, userState.mUserId) == 1;
3296         if ((magnificationTwoFingerTripleTapEnabled
3297                 != userState.isMagnificationTwoFingerTripleTapEnabledLocked())) {
3298             userState.setMagnificationTwoFingerTripleTapEnabledLocked(
3299                     magnificationTwoFingerTripleTapEnabled);
3300             return true;
3301         }
3302         return false;
3303     }
3304 
readAutoclickEnabledSettingLocked(AccessibilityUserState userState)3305     private boolean readAutoclickEnabledSettingLocked(AccessibilityUserState userState) {
3306         final boolean autoclickEnabled = Settings.Secure.getIntForUser(
3307                 mContext.getContentResolver(),
3308                 Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED,
3309                 0, userState.mUserId) == 1;
3310         if (autoclickEnabled != userState.isAutoclickEnabledLocked()) {
3311             userState.setAutoclickEnabledLocked(autoclickEnabled);
3312             return true;
3313         }
3314         return false;
3315     }
3316 
readHighTextContrastEnabledSettingLocked(AccessibilityUserState userState)3317     private boolean readHighTextContrastEnabledSettingLocked(AccessibilityUserState userState) {
3318         final boolean highTextContrastEnabled = Settings.Secure.getIntForUser(
3319                 mContext.getContentResolver(),
3320                 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, 0,
3321                 userState.mUserId) == 1;
3322         if (highTextContrastEnabled != userState.isTextHighContrastEnabledLocked()) {
3323             userState.setTextHighContrastEnabledLocked(highTextContrastEnabled);
3324             return true;
3325         }
3326         return false;
3327     }
3328 
readAudioDescriptionEnabledSettingLocked(AccessibilityUserState userState)3329     private boolean readAudioDescriptionEnabledSettingLocked(AccessibilityUserState userState) {
3330         final boolean audioDescriptionByDefaultEnabled = Settings.Secure.getIntForUser(
3331                 mContext.getContentResolver(),
3332                 Settings.Secure.ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT, 0,
3333                 userState.mUserId) == 1;
3334         if (audioDescriptionByDefaultEnabled
3335                     != userState.isAudioDescriptionByDefaultEnabledLocked()) {
3336             userState.setAudioDescriptionByDefaultEnabledLocked(audioDescriptionByDefaultEnabled);
3337             return true;
3338         }
3339         return false;
3340     }
3341 
updateTouchExplorationLocked(AccessibilityUserState userState)3342     private void updateTouchExplorationLocked(AccessibilityUserState userState) {
3343         boolean touchExplorationEnabled = mUiAutomationManager.isTouchExplorationEnabledLocked();
3344         boolean serviceHandlesDoubleTapEnabled = false;
3345         boolean requestMultiFingerGestures = false;
3346         boolean requestTwoFingerPassthrough = false;
3347         boolean sendMotionEvents = false;
3348         final int serviceCount = userState.mBoundServices.size();
3349         for (int i = 0; i < serviceCount; i++) {
3350             AccessibilityServiceConnection service = userState.mBoundServices.get(i);
3351             if (canRequestAndRequestsTouchExplorationLocked(service, userState)) {
3352                 touchExplorationEnabled = true;
3353                 serviceHandlesDoubleTapEnabled = service.isServiceHandlesDoubleTapEnabled();
3354                 requestMultiFingerGestures = service.isMultiFingerGesturesEnabled();
3355                 requestTwoFingerPassthrough = service.isTwoFingerPassthroughEnabled();
3356                 sendMotionEvents = service.isSendMotionEventsEnabled();
3357                 break;
3358             }
3359         }
3360         if (touchExplorationEnabled != userState.isTouchExplorationEnabledLocked()) {
3361             userState.setTouchExplorationEnabledLocked(touchExplorationEnabled);
3362             final long identity = Binder.clearCallingIdentity();
3363             try {
3364                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
3365                         Settings.Secure.TOUCH_EXPLORATION_ENABLED, touchExplorationEnabled ? 1 : 0,
3366                         userState.mUserId);
3367             } finally {
3368                 Binder.restoreCallingIdentity(identity);
3369             }
3370         }
3371         // Service gesture detection is turned on and off on a per-display
3372         // basis.
3373         userState.resetServiceDetectsGestures();
3374         final ArrayList<Display> displays = getValidDisplayList();
3375         for (AccessibilityServiceConnection service: userState.mBoundServices) {
3376             for (Display display : displays) {
3377                 int displayId = display.getDisplayId();
3378                 if (service.isServiceDetectsGesturesEnabled(displayId)) {
3379                     userState.setServiceDetectsGesturesEnabled(displayId, true);
3380                 }
3381             }
3382         }
3383         userState.setServiceHandlesDoubleTapLocked(serviceHandlesDoubleTapEnabled);
3384         userState.setMultiFingerGesturesLocked(requestMultiFingerGestures);
3385         userState.setTwoFingerPassthroughLocked(requestTwoFingerPassthrough);
3386         userState.setSendMotionEventsEnabled(sendMotionEvents);
3387     }
3388 
readAccessibilityShortcutKeySettingLocked(AccessibilityUserState userState)3389     private boolean readAccessibilityShortcutKeySettingLocked(AccessibilityUserState userState) {
3390         final String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
3391                 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, userState.mUserId);
3392         final Set<String> targetsFromSetting = new ArraySet<>();
3393         readColonDelimitedStringToSet(settingValue, str -> str, targetsFromSetting, false);
3394         // Fall back to device's default a11y service, only when setting is never updated.
3395         if (settingValue == null) {
3396             final String defaultService = mContext.getString(
3397                     R.string.config_defaultAccessibilityService);
3398             if (!TextUtils.isEmpty(defaultService)) {
3399                 targetsFromSetting.add(defaultService);
3400             }
3401         }
3402 
3403         final Set<String> currentTargets =
3404                 userState.getShortcutTargetsLocked(UserShortcutType.HARDWARE);
3405         if (targetsFromSetting.equals(currentTargets)) {
3406             return false;
3407         }
3408         currentTargets.clear();
3409         currentTargets.addAll(targetsFromSetting);
3410         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
3411         return true;
3412     }
3413 
readAccessibilityQsTargetsLocked(AccessibilityUserState userState)3414     private boolean readAccessibilityQsTargetsLocked(AccessibilityUserState userState) {
3415         final Set<String> targetsFromSetting = new ArraySet<>();
3416         readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_QS_TARGETS,
3417                 userState.mUserId, str -> str, targetsFromSetting);
3418 
3419         final Set<String> currentTargets =
3420                 userState.getShortcutTargetsLocked(UserShortcutType.QUICK_SETTINGS);
3421         if (targetsFromSetting.equals(currentTargets)) {
3422             return false;
3423         }
3424         userState.updateA11yQsTargetLocked(targetsFromSetting);
3425         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
3426         return true;
3427     }
3428 
readAccessibilityButtonTargetsLocked(AccessibilityUserState userState)3429     private boolean readAccessibilityButtonTargetsLocked(AccessibilityUserState userState) {
3430         final Set<String> targetsFromSetting = new ArraySet<>();
3431         readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
3432                 userState.mUserId, str -> str, targetsFromSetting);
3433 
3434         final Set<String> currentTargets =
3435                 userState.getShortcutTargetsLocked(UserShortcutType.SOFTWARE);
3436         if (targetsFromSetting.equals(currentTargets)) {
3437             return false;
3438         }
3439         currentTargets.clear();
3440         currentTargets.addAll(targetsFromSetting);
3441         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
3442         return true;
3443     }
3444 
readAccessibilityButtonTargetComponentLocked(AccessibilityUserState userState)3445     private boolean readAccessibilityButtonTargetComponentLocked(AccessibilityUserState userState) {
3446         final String componentId = Settings.Secure.getStringForUser(mContext.getContentResolver(),
3447                 Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, userState.mUserId);
3448         if (TextUtils.isEmpty(componentId)) {
3449             if (userState.getTargetAssignedToAccessibilityButton() == null) {
3450                 return false;
3451             }
3452             userState.setTargetAssignedToAccessibilityButton(null);
3453             return true;
3454         }
3455         if (componentId.equals(userState.getTargetAssignedToAccessibilityButton())) {
3456             return false;
3457         }
3458         userState.setTargetAssignedToAccessibilityButton(componentId);
3459         return true;
3460     }
3461 
readUserRecommendedUiTimeoutSettingsLocked(AccessibilityUserState userState)3462     private boolean readUserRecommendedUiTimeoutSettingsLocked(AccessibilityUserState userState) {
3463         final int nonInteractiveUiTimeout = Settings.Secure.getIntForUser(
3464                 mContext.getContentResolver(),
3465                 Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS, 0,
3466                 userState.mUserId);
3467         final int interactiveUiTimeout = Settings.Secure.getIntForUser(
3468                 mContext.getContentResolver(),
3469                 Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, 0,
3470                 userState.mUserId);
3471 
3472         mProxyManager.updateTimeoutsIfNeeded(nonInteractiveUiTimeout, interactiveUiTimeout);
3473         if (nonInteractiveUiTimeout != userState.getUserNonInteractiveUiTimeoutLocked()
3474                 || interactiveUiTimeout != userState.getUserInteractiveUiTimeoutLocked()) {
3475             userState.setUserNonInteractiveUiTimeoutLocked(nonInteractiveUiTimeout);
3476             userState.setUserInteractiveUiTimeoutLocked(interactiveUiTimeout);
3477             scheduleNotifyClientsOfServicesStateChangeLocked(userState);
3478             return true;
3479         }
3480         return false;
3481     }
3482 
3483     /**
3484      * Check if the target that will be enabled by the accessibility shortcut key is installed.
3485      * If it isn't, remove it from the list and associated setting so a side loaded service can't
3486      * spoof the package name of the default service.
3487      */
updateAccessibilityShortcutKeyTargetsLocked(AccessibilityUserState userState)3488     private void updateAccessibilityShortcutKeyTargetsLocked(AccessibilityUserState userState) {
3489         final Set<String> currentTargets =
3490                 userState.getShortcutTargetsLocked(UserShortcutType.HARDWARE);
3491         final int lastSize = currentTargets.size();
3492         if (lastSize == 0) {
3493             return;
3494         }
3495         currentTargets.removeIf(
3496                 name -> !userState.isShortcutTargetInstalledLocked(name));
3497         if (lastSize == currentTargets.size()) {
3498             return;
3499         }
3500 
3501         // Update setting key with new value.
3502         persistColonDelimitedSetToSettingLocked(
3503                 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
3504                 userState.mUserId, currentTargets, str -> str);
3505         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
3506     }
3507 
canRequestAndRequestsTouchExplorationLocked( AccessibilityServiceConnection service, AccessibilityUserState userState)3508     private boolean canRequestAndRequestsTouchExplorationLocked(
3509             AccessibilityServiceConnection service, AccessibilityUserState userState) {
3510         // Service not ready or cannot request the feature - well nothing to do.
3511         if (!service.canReceiveEventsLocked() || !service.mRequestTouchExplorationMode) {
3512             return false;
3513         }
3514         if (service.getServiceInfo().getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion
3515                 <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
3516             // Up to JB-MR1 we had a allowlist with services that can enable touch
3517             // exploration. When a service is first started we show a dialog to the
3518             // use to get a permission to allowlist the service.
3519             if (userState.mTouchExplorationGrantedServices.contains(service.mComponentName)) {
3520                 return true;
3521             } else if (mEnableTouchExplorationDialog == null
3522                     || !mEnableTouchExplorationDialog.isShowing()) {
3523                 mMainHandler.sendMessage(obtainMessage(
3524                         AccessibilityManagerService::showEnableTouchExplorationDialog,
3525                         this, service));
3526             }
3527         } else {
3528             // Starting in JB-MR2 we request an accessibility service to declare
3529             // certain capabilities in its meta-data to allow it to enable the
3530             // corresponding features.
3531             if ((service.getCapabilities()
3532                     & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) != 0) {
3533                 return true;
3534             }
3535         }
3536         return false;
3537     }
3538 
updateMagnificationLocked(AccessibilityUserState userState)3539     private void updateMagnificationLocked(AccessibilityUserState userState) {
3540         if (userState.mUserId != mCurrentUserId) {
3541             return;
3542         }
3543 
3544         if (mUiAutomationManager.suppressingAccessibilityServicesLocked()
3545                 && mMagnificationController.isFullScreenMagnificationControllerInitialized()) {
3546             getMagnificationController().getFullScreenMagnificationController().unregisterAll();
3547             return;
3548         }
3549 
3550         // Get all valid displays and register them if global magnification is enabled.
3551         // We would skip overlay display because it uses overlay window to simulate secondary
3552         // displays in one display. It's not a real display and there's no input events for it.
3553         final ArrayList<Display> displays = getValidDisplayList();
3554         if (userState.isMagnificationSingleFingerTripleTapEnabledLocked()
3555                 || (Flags.enableMagnificationMultipleFingerMultipleTapGesture()
3556                 && userState.isMagnificationTwoFingerTripleTapEnabledLocked())
3557                 || userState.isShortcutMagnificationEnabledLocked()) {
3558             for (int i = 0; i < displays.size(); i++) {
3559                 final Display display = displays.get(i);
3560                 getMagnificationController().getFullScreenMagnificationController().register(
3561                         display.getDisplayId());
3562             }
3563             return;
3564         }
3565 
3566         // Register if display has listening magnification services.
3567         for (int i = 0; i < displays.size(); i++) {
3568             final Display display = displays.get(i);
3569             final int displayId = display.getDisplayId();
3570             if (userHasListeningMagnificationServicesLocked(userState, displayId)) {
3571                 getMagnificationController().getFullScreenMagnificationController().register(
3572                         displayId);
3573             } else if (mMagnificationController.isFullScreenMagnificationControllerInitialized()) {
3574                 getMagnificationController().getFullScreenMagnificationController().unregister(
3575                         displayId);
3576             }
3577         }
3578     }
3579 
updateMagnificationConnectionIfNeeded(AccessibilityUserState userState)3580     private void updateMagnificationConnectionIfNeeded(AccessibilityUserState userState) {
3581         if (!mMagnificationController.supportWindowMagnification()) {
3582             return;
3583         }
3584 
3585         final boolean shortcutEnabled = (userState.isShortcutMagnificationEnabledLocked()
3586                 || userState.isMagnificationSingleFingerTripleTapEnabledLocked()
3587                 || (Flags.enableMagnificationMultipleFingerMultipleTapGesture()
3588                     && userState.isMagnificationTwoFingerTripleTapEnabledLocked()));
3589 
3590         final boolean createConnectionForCurrentCapability =
3591                 com.android.window.flags.Flags.alwaysDrawMagnificationFullscreenBorder()
3592                         || (userState.getMagnificationCapabilitiesLocked()
3593                                 != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
3594 
3595         final boolean connect = (shortcutEnabled && createConnectionForCurrentCapability)
3596                 || userHasMagnificationServicesLocked(userState);
3597 
3598         getMagnificationConnectionManager().requestConnection(connect);
3599     }
3600 
3601     /**
3602      * Returns whether the specified user has any services that are capable of
3603      * controlling magnification.
3604      */
userHasMagnificationServicesLocked(AccessibilityUserState userState)3605     private boolean userHasMagnificationServicesLocked(AccessibilityUserState userState) {
3606         final List<AccessibilityServiceConnection> services = userState.mBoundServices;
3607         for (int i = 0, count = services.size(); i < count; i++) {
3608             final AccessibilityServiceConnection service = services.get(i);
3609             if (mSecurityPolicy.canControlMagnification(service)) {
3610                 return true;
3611             }
3612         }
3613         return false;
3614     }
3615 
3616     /**
3617      * Returns whether the specified user has any services that are capable of
3618      * controlling magnification and are actively listening for magnification updates.
3619      */
userHasListeningMagnificationServicesLocked(AccessibilityUserState userState, int displayId)3620     private boolean userHasListeningMagnificationServicesLocked(AccessibilityUserState userState,
3621             int displayId) {
3622         final List<AccessibilityServiceConnection> services = userState.mBoundServices;
3623         for (int i = 0, count = services.size(); i < count; i++) {
3624             final AccessibilityServiceConnection service = services.get(i);
3625             if (mSecurityPolicy.canControlMagnification(service)
3626                     && service.isMagnificationCallbackEnabled(displayId)) {
3627                 return true;
3628             }
3629         }
3630         return false;
3631     }
3632 
updateFingerprintGestureHandling(AccessibilityUserState userState)3633     private void updateFingerprintGestureHandling(AccessibilityUserState userState) {
3634         final List<AccessibilityServiceConnection> services;
3635         synchronized (mLock) {
3636             services = userState.mBoundServices;
3637             if ((mFingerprintGestureDispatcher == null)
3638                     &&  mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
3639                 // Only create the controller when a service wants to use the feature
3640                 int numServices = services.size();
3641                 for (int i = 0; i < numServices; i++) {
3642                     if (services.get(i).isCapturingFingerprintGestures()) {
3643                         IFingerprintService service = null;
3644                         final long identity = Binder.clearCallingIdentity();
3645                         try {
3646                             service = IFingerprintService.Stub.asInterface(
3647                                     ServiceManager.getService(Context.FINGERPRINT_SERVICE));
3648                         } finally {
3649                             Binder.restoreCallingIdentity(identity);
3650                         }
3651                         if (service != null) {
3652                             mFingerprintGestureDispatcher = new FingerprintGestureDispatcher(
3653                                     service, mContext.getResources(), mLock);
3654                             break;
3655                         }
3656                     }
3657                 }
3658             }
3659         }
3660         if (mFingerprintGestureDispatcher != null) {
3661             mFingerprintGestureDispatcher.updateClientList(services);
3662         }
3663     }
3664 
3665     /**
3666      * 1) Update accessibility button availability to accessibility services.
3667      * 2) Check if the target that will be enabled by the accessibility button is installed.
3668      *    If it isn't, remove it from the list and associated setting so a side loaded service can't
3669      *    spoof the package name of the default service.
3670      */
updateAccessibilityButtonTargetsLocked(AccessibilityUserState userState)3671     private void updateAccessibilityButtonTargetsLocked(AccessibilityUserState userState) {
3672         // Update accessibility button availability.
3673         for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
3674             final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
3675             if (service.mRequestAccessibilityButton) {
3676                 service.notifyAccessibilityButtonAvailabilityChangedLocked(
3677                         service.isAccessibilityButtonAvailableLocked(userState));
3678             }
3679         }
3680 
3681         final Set<String> currentTargets =
3682                 userState.getShortcutTargetsLocked(UserShortcutType.SOFTWARE);
3683         final int lastSize = currentTargets.size();
3684         if (lastSize == 0) {
3685             return;
3686         }
3687         currentTargets.removeIf(
3688                 name -> !userState.isShortcutTargetInstalledLocked(name));
3689         if (lastSize == currentTargets.size()) {
3690             return;
3691         }
3692 
3693         // Update setting key with new value.
3694         persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
3695                 userState.mUserId, currentTargets, str -> str);
3696         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
3697     }
3698 
3699     /**
3700      * 1) Check if the service assigned to accessibility button target sdk version > Q.
3701      *    If it isn't, remove it from the list and associated setting.
3702      *    (It happens when an accessibility service package is downgraded.)
3703      * 2) For a service targeting sdk version > Q and requesting a11y button, it should be in the
3704      *    enabled list if's assigned to a11y button.
3705      *    (It happens when an accessibility service package is same graded, and updated requesting
3706      *     a11y button flag)
3707      * 3) Check if an enabled service targeting sdk version > Q and requesting a11y button is
3708      *    assigned to a shortcut. If it isn't, assigns it to the accessibility button.
3709      *    (It happens when an enabled accessibility service package is upgraded.)
3710      *
3711      * @param packageName The package name to check, or {@code null} to check all services.
3712      * @param restoreFromSdkInt The target sdk version of the restored source device, or {@code 0}
3713      *                          if the caller is not related to the restore.
3714      */
migrateAccessibilityButtonSettingsIfNecessaryLocked( AccessibilityUserState userState, @Nullable String packageName, int restoreFromSdkInt)3715     private void migrateAccessibilityButtonSettingsIfNecessaryLocked(
3716             AccessibilityUserState userState, @Nullable String packageName, int restoreFromSdkInt) {
3717         // No need to migrate settings if they are restored from a version after Q.
3718         if (restoreFromSdkInt > Build.VERSION_CODES.Q) {
3719             return;
3720         }
3721         final Set<String> buttonTargets =
3722                 userState.getShortcutTargetsLocked(UserShortcutType.SOFTWARE);
3723         int lastSize = buttonTargets.size();
3724         buttonTargets.removeIf(name -> {
3725             if (packageName != null && name != null && !name.contains(packageName)) {
3726                 return false;
3727             }
3728             final ComponentName componentName = ComponentName.unflattenFromString(name);
3729             if (componentName == null) {
3730                 return false;
3731             }
3732             final AccessibilityServiceInfo serviceInfo =
3733                     userState.getInstalledServiceInfoLocked(componentName);
3734             if (serviceInfo == null) {
3735                 return false;
3736             }
3737             if (serviceInfo.getResolveInfo().serviceInfo.applicationInfo
3738                     .targetSdkVersion <= Build.VERSION_CODES.Q) {
3739                 // A11y services targeting sdk version <= Q should not be in the list.
3740                 Slog.v(LOG_TAG, "Legacy service " + componentName
3741                         + " should not in the button");
3742                 return true;
3743             }
3744             final boolean requestA11yButton = (serviceInfo.flags
3745                     & FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
3746             if (requestA11yButton && !userState.mEnabledServices.contains(componentName)) {
3747                 // An a11y service targeting sdk version > Q and request A11y button and is assigned
3748                 // to a11y btn should be in the enabled list.
3749                 Slog.v(LOG_TAG, "Service requesting a11y button and be assigned to the button"
3750                         + componentName + " should be enabled state");
3751                 return true;
3752             }
3753             return false;
3754         });
3755         boolean changed = (lastSize != buttonTargets.size());
3756         lastSize = buttonTargets.size();
3757 
3758         final Set<String> shortcutKeyTargets =
3759                 userState.getShortcutTargetsLocked(UserShortcutType.HARDWARE);
3760         final Set<String> qsShortcutTargets =
3761                 userState.getShortcutTargetsLocked(UserShortcutType.QUICK_SETTINGS);
3762         userState.mEnabledServices.forEach(componentName -> {
3763             if (packageName != null && componentName != null
3764                     && !packageName.equals(componentName.getPackageName())) {
3765                 return;
3766             }
3767             final AccessibilityServiceInfo serviceInfo =
3768                     userState.getInstalledServiceInfoLocked(componentName);
3769             if (serviceInfo == null) {
3770                 return;
3771             }
3772             final boolean requestA11yButton = (serviceInfo.flags
3773                     & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
3774             if (!(serviceInfo.getResolveInfo().serviceInfo.applicationInfo
3775                     .targetSdkVersion > Build.VERSION_CODES.Q && requestA11yButton)) {
3776                 return;
3777             }
3778             final String serviceName = componentName.flattenToString();
3779             if (TextUtils.isEmpty(serviceName)) {
3780                 return;
3781             }
3782             if (doesShortcutTargetsStringContain(buttonTargets, serviceName)
3783                     || doesShortcutTargetsStringContain(shortcutKeyTargets, serviceName)
3784                     || doesShortcutTargetsStringContain(qsShortcutTargets, serviceName)) {
3785                 return;
3786             }
3787             // For enabled a11y services targeting sdk version > Q and requesting a11y button should
3788             // be assigned to a shortcut.
3789             Slog.v(LOG_TAG, "A enabled service requesting a11y button " + componentName
3790                     + " should be assign to the button or shortcut.");
3791             buttonTargets.add(serviceName);
3792         });
3793         changed |= (lastSize != buttonTargets.size());
3794         if (!changed) {
3795             return;
3796         }
3797 
3798         // Update setting key with new value.
3799         persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
3800                 userState.mUserId, buttonTargets, str -> str);
3801         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
3802     }
3803 
3804     /**
3805      * Update the Settings.Secure.ACCESSIBILITY_QS_TARGETS so that it only contains valid content,
3806      * and a side loaded service can't spoof the package name of the default service.
3807      * <p>
3808      * 1. Remove the target if the target is no longer installed on the device <br/>
3809      * 2. Add the target if the target is enabled and the target's tile is in the QS Panel <br/>
3810      * </p>
3811      */
updateAccessibilityQsTargetsLocked(AccessibilityUserState userState)3812     private void updateAccessibilityQsTargetsLocked(AccessibilityUserState userState) {
3813         if (!android.view.accessibility.Flags.a11yQsShortcut()) {
3814             return;
3815         }
3816 
3817         final Set<String> targets =
3818                 userState.getShortcutTargetsLocked(UserShortcutType.QUICK_SETTINGS);
3819 
3820         // Removes the targets that are no longer installed on the device.
3821         boolean somethingChanged = targets.removeIf(
3822                 name -> !userState.isShortcutTargetInstalledLocked(name));
3823         // Add the target if the a11y service is enabled and the tile exist in QS panel
3824         Set<ComponentName> enabledServices = userState.getEnabledServicesLocked();
3825         Map<ComponentName, ComponentName> a11yFeatureToTileService =
3826                 userState.getA11yFeatureToTileService();
3827         Set<ComponentName> currentA11yTilesInQsPanel = userState.getA11yQsTilesInQsPanel();
3828         for (ComponentName enabledService : enabledServices) {
3829             ComponentName tileService =
3830                     a11yFeatureToTileService.getOrDefault(enabledService, null);
3831             if (tileService != null && currentA11yTilesInQsPanel.contains(tileService)) {
3832                 somethingChanged |= targets.add(enabledService.flattenToString());
3833             }
3834         }
3835 
3836         if (!somethingChanged) {
3837             return;
3838         }
3839         userState.updateA11yQsTargetLocked(targets);
3840 
3841         // Update setting key with new value.
3842         persistColonDelimitedSetToSettingLocked(
3843                 Settings.Secure.ACCESSIBILITY_QS_TARGETS,
3844                 userState.mUserId, targets, str -> str);
3845         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
3846     }
3847 
3848     /**
3849      * Remove the shortcut target for the unbound service which is requesting accessibility button
3850      * and targeting sdk > Q from the accessibility button and shortcut.
3851      *
3852      * @param userState The accessibility user state.
3853      * @param service The unbound service.
3854      */
removeShortcutTargetForUnboundServiceLocked(AccessibilityUserState userState, AccessibilityServiceConnection service)3855     private void removeShortcutTargetForUnboundServiceLocked(AccessibilityUserState userState,
3856             AccessibilityServiceConnection service) {
3857         if (!service.mRequestAccessibilityButton
3858                 || service.getServiceInfo().getResolveInfo().serviceInfo.applicationInfo
3859                 .targetSdkVersion <= Build.VERSION_CODES.Q) {
3860             return;
3861         }
3862 
3863         final List<Pair<Integer, String>> shortcutTypeAndShortcutSetting = new ArrayList<>(3);
3864         shortcutTypeAndShortcutSetting.add(
3865                 new Pair<>(UserShortcutType.HARDWARE,
3866                         Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE));
3867         shortcutTypeAndShortcutSetting.add(
3868                 new Pair<>(UserShortcutType.SOFTWARE,
3869                         Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS));
3870         if (android.view.accessibility.Flags.a11yQsShortcut()) {
3871             shortcutTypeAndShortcutSetting.add(
3872                     new Pair<>(UserShortcutType.QUICK_SETTINGS,
3873                             Settings.Secure.ACCESSIBILITY_QS_TARGETS));
3874         }
3875 
3876         final ComponentName serviceName = service.getComponentName();
3877         for (Pair<Integer, String> shortcutTypePair : shortcutTypeAndShortcutSetting) {
3878             int shortcutType = shortcutTypePair.first;
3879             String shortcutSettingName = shortcutTypePair.second;
3880             if (userState.removeShortcutTargetLocked(shortcutType, serviceName)) {
3881                 final Set<String> currentTargets = userState.getShortcutTargetsLocked(shortcutType);
3882                 persistColonDelimitedSetToSettingLocked(
3883                         shortcutSettingName,
3884                         userState.mUserId, currentTargets, str -> str);
3885 
3886                 if (shortcutType != UserShortcutType.QUICK_SETTINGS) {
3887                     continue;
3888                 }
3889 
3890                 ComponentName tileService =
3891                         userState.getA11yFeatureToTileService().getOrDefault(serviceName, null);
3892 
3893                 final StatusBarManagerInternal statusBarManagerInternal =
3894                         LocalServices.getService(StatusBarManagerInternal.class);
3895                 // In case it's not initialized yet
3896                 if (statusBarManagerInternal == null || tileService == null) {
3897                     continue;
3898                 }
3899                 mMainHandler.sendMessage(obtainMessage(StatusBarManagerInternal::removeQsTile,
3900                         statusBarManagerInternal, tileService));
3901             }
3902         }
3903     }
3904 
updateRecommendedUiTimeoutLocked(AccessibilityUserState userState)3905     private void updateRecommendedUiTimeoutLocked(AccessibilityUserState userState) {
3906         int newNonInteractiveUiTimeout = userState.getUserNonInteractiveUiTimeoutLocked();
3907         int newInteractiveUiTimeout = userState.getUserInteractiveUiTimeoutLocked();
3908         // read from a11y services if user does not specify value
3909         if (newNonInteractiveUiTimeout == 0 || newInteractiveUiTimeout == 0) {
3910             int serviceNonInteractiveUiTimeout = 0;
3911             int serviceInteractiveUiTimeout = 0;
3912             final List<AccessibilityServiceConnection> services = userState.mBoundServices;
3913             for (int i = 0; i < services.size(); i++) {
3914                 int timeout = services.get(i).getServiceInfo().getInteractiveUiTimeoutMillis();
3915                 if (serviceInteractiveUiTimeout < timeout) {
3916                     serviceInteractiveUiTimeout = timeout;
3917                 }
3918                 timeout = services.get(i).getServiceInfo().getNonInteractiveUiTimeoutMillis();
3919                 if (serviceNonInteractiveUiTimeout < timeout) {
3920                     serviceNonInteractiveUiTimeout = timeout;
3921                 }
3922             }
3923             if (newNonInteractiveUiTimeout == 0) {
3924                 newNonInteractiveUiTimeout = serviceNonInteractiveUiTimeout;
3925             }
3926             if (newInteractiveUiTimeout == 0) {
3927                 newInteractiveUiTimeout = serviceInteractiveUiTimeout;
3928             }
3929         }
3930         userState.setNonInteractiveUiTimeoutLocked(newNonInteractiveUiTimeout);
3931         userState.setInteractiveUiTimeoutLocked(newInteractiveUiTimeout);
3932     }
3933 
3934     @Override
getKeyEventDispatcher()3935     public KeyEventDispatcher getKeyEventDispatcher() {
3936         if (mKeyEventDispatcher == null) {
3937             mKeyEventDispatcher = new KeyEventDispatcher(
3938                     mMainHandler, MainHandler.MSG_SEND_KEY_EVENT_TO_INPUT_FILTER, mLock,
3939                     mPowerManager);
3940         }
3941         return mKeyEventDispatcher;
3942     }
3943 
3944     @Override
3945     @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
getPendingIntentActivity(Context context, int requestCode, Intent intent, int flags)3946     public PendingIntent getPendingIntentActivity(Context context, int requestCode, Intent intent,
3947             int flags) {
3948         return PendingIntent.getActivity(context, requestCode, intent, flags);
3949     }
3950 
3951     /**
3952      * AIDL-exposed method to be called when the accessibility shortcut key is enabled. Requires
3953      * permission to write secure settings, since someone with that permission can enable
3954      * accessibility services themselves.
3955      *
3956      * @param targetName The flattened {@link ComponentName} string or the class name of a system
3957      *        class implementing a supported accessibility feature, or {@code null} if there's no
3958      *        specified target.
3959      */
3960     @EnforcePermission(MANAGE_ACCESSIBILITY)
3961     @Override
performAccessibilityShortcut(String targetName)3962     public void performAccessibilityShortcut(String targetName) {
3963         performAccessibilityShortcut_enforcePermission();
3964         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
3965             mTraceManager.logTrace(LOG_TAG + ".performAccessibilityShortcut",
3966                     FLAGS_ACCESSIBILITY_MANAGER, "targetName=" + targetName);
3967         }
3968 
3969         mMainHandler.sendMessage(obtainMessage(
3970                 AccessibilityManagerService::performAccessibilityShortcutInternal, this,
3971                 Display.DEFAULT_DISPLAY, UserShortcutType.HARDWARE, targetName));
3972     }
3973 
3974     /**
3975      * Perform the accessibility shortcut action.
3976      *
3977      * @param shortcutType The shortcut type.
3978      * @param displayId The display id of the accessibility button.
3979      * @param targetName The flattened {@link ComponentName} string or the class name of a system
3980      *        class implementing a supported accessibility feature, or {@code null} if there's no
3981      *        specified target.
3982      */
performAccessibilityShortcutInternal(int displayId, @UserShortcutType int shortcutType, @Nullable String targetName)3983     private void performAccessibilityShortcutInternal(int displayId,
3984             @UserShortcutType int shortcutType, @Nullable String targetName) {
3985         final List<String> shortcutTargets = getAccessibilityShortcutTargetsInternal(shortcutType);
3986         if (shortcutTargets.isEmpty()) {
3987             Slog.d(LOG_TAG, "No target to perform shortcut, shortcutType=" + shortcutType);
3988             return;
3989         }
3990         // In case the caller specified a target name
3991         if (targetName != null && !doesShortcutTargetsStringContain(shortcutTargets, targetName)) {
3992             Slog.v(LOG_TAG, "Perform shortcut failed, invalid target name:" + targetName);
3993             targetName = null;
3994         }
3995         if (targetName == null) {
3996             // In case there are many targets assigned to the given shortcut.
3997             if (shortcutTargets.size() > 1) {
3998                 showAccessibilityTargetsSelection(displayId, shortcutType);
3999                 return;
4000             }
4001             targetName = shortcutTargets.get(0);
4002         }
4003         // In case user assigned magnification to the given shortcut.
4004         if (targetName.equals(MAGNIFICATION_CONTROLLER_NAME)) {
4005             final boolean enabled =
4006                     !getMagnificationController().getFullScreenMagnificationController()
4007                             .isActivated(displayId);
4008             logAccessibilityShortcutActivated(mContext, MAGNIFICATION_COMPONENT_NAME, shortcutType,
4009                     enabled);
4010             sendAccessibilityButtonToInputFilter(displayId);
4011             return;
4012         }
4013         final ComponentName targetComponentName = ComponentName.unflattenFromString(targetName);
4014         if (targetComponentName == null) {
4015             Slog.d(LOG_TAG, "Perform shortcut failed, invalid target name:" + targetName);
4016             return;
4017         }
4018         // In case user assigned an accessibility framework feature to the given shortcut.
4019         if (performAccessibilityFrameworkFeature(displayId, targetComponentName, shortcutType)) {
4020             return;
4021         }
4022         // In case user assigned an accessibility shortcut target to the given shortcut.
4023         if (performAccessibilityShortcutTargetActivity(displayId, targetComponentName)) {
4024             logAccessibilityShortcutActivated(mContext, targetComponentName, shortcutType);
4025             return;
4026         }
4027         // in case user assigned an accessibility service to the given shortcut.
4028         if (performAccessibilityShortcutTargetService(
4029                 displayId, shortcutType, targetComponentName)) {
4030             return;
4031         }
4032     }
4033 
performAccessibilityFrameworkFeature(int displayId, ComponentName assignedTarget, @UserShortcutType int shortcutType)4034     private boolean performAccessibilityFrameworkFeature(int displayId,
4035             ComponentName assignedTarget, @UserShortcutType int shortcutType) {
4036         final Map<ComponentName, FrameworkFeatureInfo> frameworkFeatureMap =
4037                 AccessibilityShortcutController.getFrameworkShortcutFeaturesMap();
4038         if (!frameworkFeatureMap.containsKey(assignedTarget)) {
4039             return false;
4040         }
4041         final FrameworkFeatureInfo featureInfo = frameworkFeatureMap.get(assignedTarget);
4042         final SettingStringHelper setting = new SettingStringHelper(mContext.getContentResolver(),
4043                 featureInfo.getSettingKey(), mCurrentUserId);
4044 
4045         if (featureInfo instanceof LaunchableFrameworkFeatureInfo) {
4046             logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType,
4047                     /* serviceEnabled= */ true);
4048             launchAccessibilityFrameworkFeature(displayId, assignedTarget);
4049             return true;
4050         }
4051 
4052         // Assuming that the default state will be to have the feature off
4053         if (!TextUtils.equals(featureInfo.getSettingOnValue(), setting.read())) {
4054             logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType,
4055                     /* serviceEnabled= */ true);
4056             setting.write(featureInfo.getSettingOnValue());
4057         } else {
4058             logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType,
4059                     /* serviceEnabled= */ false);
4060             setting.write(featureInfo.getSettingOffValue());
4061         }
4062         return true;
4063     }
4064 
performAccessibilityShortcutTargetActivity(int displayId, ComponentName assignedTarget)4065     private boolean performAccessibilityShortcutTargetActivity(int displayId,
4066             ComponentName assignedTarget) {
4067         synchronized (mLock) {
4068             final AccessibilityUserState userState = getCurrentUserStateLocked();
4069             for (int i = 0; i < userState.mInstalledShortcuts.size(); i++) {
4070                 final AccessibilityShortcutInfo shortcutInfo = userState.mInstalledShortcuts.get(i);
4071                 if (!shortcutInfo.getComponentName().equals(assignedTarget)) {
4072                     continue;
4073                 }
4074                 launchShortcutTargetActivity(displayId, assignedTarget);
4075                 return true;
4076             }
4077         }
4078         return false;
4079     }
4080 
4081     /**
4082      * Perform accessibility service shortcut action.
4083      *
4084      * 1) For {@link UserShortcutType#SOFTWARE} type and services targeting sdk
4085      *    version <= Q: callbacks to accessibility service if service is bounded and requests
4086      *    accessibility button.
4087      * 2) For {@link UserShortcutType#HARDWARE} type and service targeting sdk
4088      *    version <= Q: turns on / off the accessibility service.
4089      * 3) For {@link UserShortcutType#HARDWARE} type and service targeting sdk
4090      *    version > Q and request accessibility button: turn on the accessibility service if it's
4091      *    not in the enabled state.
4092      *    (It'll happen when a service is disabled and assigned to shortcut then upgraded.)
4093      * 4) For services targeting sdk version > Q:
4094      *    a) Turns on / off the accessibility service, if service does not request accessibility
4095      *       button.
4096      *    b) Callbacks to accessibility service if service is bounded and requests accessibility
4097      *       button.
4098      */
performAccessibilityShortcutTargetService(int displayId, @UserShortcutType int shortcutType, ComponentName assignedTarget)4099     private boolean performAccessibilityShortcutTargetService(int displayId,
4100             @UserShortcutType int shortcutType, ComponentName assignedTarget) {
4101         synchronized (mLock) {
4102             final AccessibilityUserState userState = getCurrentUserStateLocked();
4103             final AccessibilityServiceInfo installedServiceInfo =
4104                     userState.getInstalledServiceInfoLocked(assignedTarget);
4105             if (installedServiceInfo == null) {
4106                 Slog.d(LOG_TAG, "Perform shortcut failed, invalid component name:"
4107                         + assignedTarget);
4108                 return false;
4109             }
4110 
4111             final AccessibilityServiceConnection serviceConnection =
4112                     userState.getServiceConnectionLocked(assignedTarget);
4113             final int targetSdk = installedServiceInfo.getResolveInfo()
4114                     .serviceInfo.applicationInfo.targetSdkVersion;
4115             final boolean requestA11yButton = (installedServiceInfo.flags
4116                     & FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
4117             // Turns on / off the accessibility service
4118             if ((targetSdk <= Build.VERSION_CODES.Q && shortcutType == UserShortcutType.HARDWARE)
4119                     || (targetSdk > Build.VERSION_CODES.Q && !requestA11yButton)) {
4120                 if (serviceConnection == null) {
4121                     logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType,
4122                             /* serviceEnabled= */ true);
4123                     enableAccessibilityServiceLocked(assignedTarget, mCurrentUserId);
4124 
4125                 } else {
4126                     logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType,
4127                             /* serviceEnabled= */ false);
4128                     disableAccessibilityServiceLocked(assignedTarget, mCurrentUserId);
4129                 }
4130                 return true;
4131             }
4132             if (shortcutType == UserShortcutType.HARDWARE && targetSdk > Build.VERSION_CODES.Q
4133                     && requestA11yButton) {
4134                 if (!userState.getEnabledServicesLocked().contains(assignedTarget)) {
4135                     enableAccessibilityServiceLocked(assignedTarget, mCurrentUserId);
4136                     return true;
4137                 }
4138             }
4139             // Callbacks to a11y service if it's bounded and requests a11y button.
4140             if (serviceConnection == null
4141                     || !userState.mBoundServices.contains(serviceConnection)
4142                     || !serviceConnection.mRequestAccessibilityButton) {
4143                 Slog.d(LOG_TAG, "Perform shortcut failed, service is not ready:"
4144                         + assignedTarget);
4145                 return false;
4146             }
4147             // ServiceConnection means service enabled.
4148             logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType,
4149                     /* serviceEnabled= */ true);
4150             serviceConnection.notifyAccessibilityButtonClickedLocked(displayId);
4151             return true;
4152         }
4153     }
4154 
launchAccessibilityFrameworkFeature(int displayId, ComponentName assignedTarget)4155     private void launchAccessibilityFrameworkFeature(int displayId, ComponentName assignedTarget) {
4156         if (assignedTarget.equals(ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME)) {
4157             //import com.android.systemui.Flags;
4158             if (com.android.systemui.Flags.hearingAidsQsTileDialog()) {
4159                 launchHearingDevicesDialog();
4160             } else {
4161                 launchAccessibilitySubSettings(displayId,
4162                         ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME);
4163             }
4164         }
4165     }
4166 
4167     /**
4168      * Turns on or off a shortcut type of the accessibility features. The {@code shortcutTypes} is a
4169      * flag that contains values defined in the
4170      * {@link ShortcutConstants.USER_SHORTCUT_TYPES}.
4171      *
4172      * @hide
4173      */
4174     @Override
4175     @EnforcePermission(MANAGE_ACCESSIBILITY)
enableShortcutsForTargets( boolean enable, @UserShortcutType int shortcutTypes, @NonNull List<String> shortcutTargets, @UserIdInt int userId)4176     public void enableShortcutsForTargets(
4177             boolean enable, @UserShortcutType int shortcutTypes,
4178             @NonNull List<String> shortcutTargets, @UserIdInt int userId) {
4179         enableShortcutsForTargets_enforcePermission();
4180         for (int shortcutType : USER_SHORTCUT_TYPES) {
4181             if ((shortcutTypes & shortcutType) == shortcutType) {
4182                 enableShortcutForTargets(enable, shortcutType, shortcutTargets, userId);
4183             }
4184         }
4185     }
4186 
enableShortcutForTargets( boolean enable, @UserShortcutType int shortcutType, @NonNull List<String> shortcutTargets, @UserIdInt int userId)4187     private void enableShortcutForTargets(
4188             boolean enable, @UserShortcutType int shortcutType,
4189             @NonNull List<String> shortcutTargets, @UserIdInt int userId) {
4190         final String shortcutTypeSettingKey = ShortcutUtils.convertToKey(shortcutType);
4191         if (shortcutType == UserShortcutType.TRIPLETAP
4192                 || shortcutType == UserShortcutType.TWOFINGER_DOUBLETAP) {
4193             for (String target : shortcutTargets) {
4194                 if (MAGNIFICATION_CONTROLLER_NAME.equals(target)) {
4195                     persistIntToSetting(
4196                             userId,
4197                             shortcutTypeSettingKey,
4198                             enable ? AccessibilityUtils.State.ON : AccessibilityUtils.State.OFF);
4199                 } else {
4200                     Slog.w(LOG_TAG,
4201                             "Triple tap or two-fingers double-tap is not supported for " + target);
4202                 }
4203             }
4204             return;
4205         }
4206         Set<String> validNewTargets;
4207         Set<String> currentTargets;
4208 
4209         Map<ComponentName, ComponentName> featureToTileMap =
4210                 getA11yFeatureToTileMapInternal(userId);
4211         synchronized (mLock) {
4212             AccessibilityUserState userState = getUserStateLocked(userId);
4213             currentTargets =
4214                     ShortcutUtils.getShortcutTargetsFromSettings(mContext, shortcutType, userId);
4215 
4216             Set<String> newTargets = new ArraySet<>(currentTargets);
4217             if (enable) {
4218                 newTargets.addAll(shortcutTargets);
4219             } else {
4220                 newTargets.removeAll(shortcutTargets);
4221             }
4222             validNewTargets = newTargets;
4223 
4224             // filter out targets that doesn't have qs shortcut
4225             if (shortcutType == UserShortcutType.QUICK_SETTINGS) {
4226                 validNewTargets = newTargets.stream().filter(target -> {
4227                     ComponentName targetComponent = ComponentName.unflattenFromString(target);
4228                     return featureToTileMap.containsKey(targetComponent);
4229                 }).collect(Collectors.toUnmodifiableSet());
4230             }
4231 
4232             if (currentTargets.equals(validNewTargets)) {
4233                 return;
4234             }
4235             persistColonDelimitedSetToSettingLocked(
4236                     shortcutTypeSettingKey,
4237                     userId,
4238                     validNewTargets,
4239                     str -> str,
4240                     /* defaultEmptyString= */ ""
4241             );
4242 
4243             if (shortcutType == UserShortcutType.QUICK_SETTINGS) {
4244                 int numOfFeatureChanged = Math.abs(currentTargets.size() - validNewTargets.size());
4245                 logMetricForQsShortcutConfiguration(enable, numOfFeatureChanged);
4246                 userState.updateA11yQsTargetLocked(validNewTargets);
4247                 scheduleNotifyClientsOfServicesStateChangeLocked(userState);
4248                 onUserStateChangedLocked(userState);
4249             }
4250         }
4251         final long identity = Binder.clearCallingIdentity();
4252         try {
4253             ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState(
4254                     mContext, new ArraySet<>(shortcutTargets), userId);
4255         } finally {
4256             Binder.restoreCallingIdentity(identity);
4257         }
4258 
4259         // Add or Remove tile in QS Panel
4260         if (shortcutType == UserShortcutType.QUICK_SETTINGS) {
4261             mMainHandler.sendMessage(obtainMessage(
4262                     AccessibilityManagerService::updateA11yTileServicesInQuickSettingsPanel,
4263                     this, validNewTargets, currentTargets, userId));
4264         }
4265 
4266         if (!enable) {
4267             return;
4268         }
4269         if (shortcutType == UserShortcutType.HARDWARE) {
4270             skipVolumeShortcutDialogTimeoutRestriction(userId);
4271             if (com.android.server.accessibility.Flags.enableHardwareShortcutDisablesWarning()) {
4272                 persistIntToSetting(
4273                         userId,
4274                         Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
4275                         AccessibilityShortcutController.DialogStatus.SHOWN
4276                 );
4277             }
4278         } else if (shortcutType == UserShortcutType.SOFTWARE) {
4279             // Update the A11y FAB size to large when the Magnification shortcut is
4280             // enabled and the user hasn't changed the floating button size
4281             if (shortcutTargets.contains(MAGNIFICATION_CONTROLLER_NAME)
4282                     && Settings.Secure.getIntForUser(mContext.getContentResolver(),
4283                     Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
4284                     FloatingMenuSize.UNKNOWN, userId) == FloatingMenuSize.UNKNOWN) {
4285                 persistIntToSetting(
4286                         userId,
4287                         Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
4288                         FloatingMenuSize.LARGE);
4289             }
4290         }
4291     }
4292 
4293     /**
4294      * Add or remove the TileServices of the a11y features in the Quick Settings panel based on the
4295      * changes in the new targets and current targets.
4296      *
4297      * <p>
4298      * The framework tiles implemented in the SysUi are automatically added/removed via the
4299      * SystemUI's AutoAddable framework. This method only handles updating the TileServices
4300      * provided by AccessibilityService or Accessibility Activity.
4301      * </p>
4302      *
4303      * @see com.android.systemui.qs.pipeline.domain.model.AutoAddable AutoAddable QS Tiles
4304      */
updateA11yTileServicesInQuickSettingsPanel( Set<String> newQsTargets, Set<String> currentQsTargets, @UserIdInt int userId)4305     private void updateA11yTileServicesInQuickSettingsPanel(
4306             Set<String> newQsTargets,
4307             Set<String> currentQsTargets, @UserIdInt int userId) {
4308         // Call StatusBarManager to add/remove tiles
4309         final StatusBarManagerInternal statusBarManagerInternal =
4310                 LocalServices.getService(StatusBarManagerInternal.class);
4311         // In case it's not initialized yet
4312         if (statusBarManagerInternal == null) {
4313             return;
4314         }
4315 
4316         Map<ComponentName, ComponentName> a11yFeatureToTileMap =
4317                 getA11yFeatureToTileMapInternal(userId);
4318         Set<String> targetWithNoTile = new ArraySet<>();
4319 
4320         // Add TileServices to QS Panel that are added to the new targets
4321         newQsTargets.stream()
4322                 .filter(target -> !currentQsTargets.contains(target))
4323                 .forEach(
4324                         target -> {
4325                             ComponentName targetComponent =
4326                                     ComponentName.unflattenFromString(target);
4327                             if (targetComponent == null
4328                                     || !a11yFeatureToTileMap.containsKey(targetComponent)) {
4329                                 targetWithNoTile.add(target);
4330                                 return;
4331                             }
4332 
4333                             if (ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE.containsKey(
4334                                     targetComponent)) {
4335                                 // a11y framework tile is handled by the SysUi autoaddable framework
4336                                 return;
4337                             }
4338                             statusBarManagerInternal.addQsTileToFrontOrEnd(
4339                                     a11yFeatureToTileMap.get(targetComponent), /* end= */ true);
4340                         }
4341                 );
4342 
4343         // Remove TileServices from QS Panel that are no longer in the new targets.
4344         currentQsTargets.stream()
4345                 .filter(target -> !newQsTargets.contains(target))
4346                 .forEach(
4347                         target -> {
4348                             ComponentName targetComponent =
4349                                     ComponentName.unflattenFromString(target);
4350                             if (targetComponent == null
4351                                     || !a11yFeatureToTileMap.containsKey(targetComponent)) {
4352                                 targetWithNoTile.add(target);
4353                                 return;
4354                             }
4355 
4356                             if (ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE.containsKey(
4357                                     targetComponent)) {
4358                                 // a11y framework tile is handled by the SysUi autoaddable framework
4359                                 return;
4360                             }
4361                             statusBarManagerInternal.removeQsTile(
4362                                     a11yFeatureToTileMap.get(targetComponent));
4363                         }
4364                 );
4365 
4366         if (!targetWithNoTile.isEmpty()) {
4367             Slog.e(LOG_TAG,
4368                     "Unable to add/remove Tiles for a11y features: " + targetWithNoTile
4369                             + "as the Tiles aren't provided");
4370         }
4371     }
4372 
4373     @Override
4374     @EnforcePermission(MANAGE_ACCESSIBILITY)
getA11yFeatureToTileMap(@serIdInt int userId)4375     public Bundle getA11yFeatureToTileMap(@UserIdInt int userId) {
4376         getA11yFeatureToTileMap_enforcePermission();
4377         Bundle bundle = new Bundle();
4378         Map<ComponentName, ComponentName> a11yFeatureToTile =
4379                 getA11yFeatureToTileMapInternal(userId);
4380         for (Map.Entry<ComponentName, ComponentName> entry : a11yFeatureToTile.entrySet()) {
4381             bundle.putParcelable(entry.getKey().flattenToString(), entry.getValue());
4382         }
4383         return bundle;
4384     }
4385 
4386 
4387 
4388     /**
4389      * Returns accessibility feature's component and the provided tile map. This includes the
4390      * TileService provided by the AccessibilityService or Accessibility Activity and the tile
4391      * component provided by the framework's feature.
4392      *
4393      * @return a map of a feature's component name, and its provided tile's component name. The
4394      * returned map's keys and values are not null. If a feature doesn't provide a tile, it won't
4395      * have an entry in this map.
4396      *
4397      * @see ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE
4398      */
4399     @NonNull
getA11yFeatureToTileMapInternal( @serIdInt int userId)4400     private Map<ComponentName, ComponentName> getA11yFeatureToTileMapInternal(
4401             @UserIdInt int userId) {
4402         final Map<ComponentName, ComponentName> a11yFeatureToTileService;
4403         Map<ComponentName, ComponentName> a11yFeatureToTile = new ArrayMap<>();
4404         final int resolvedUserId;
4405 
4406         synchronized (mLock) {
4407             resolvedUserId = mSecurityPolicy
4408                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
4409             AccessibilityUserState userState = getUserStateLocked(resolvedUserId);
4410             a11yFeatureToTileService = userState.getA11yFeatureToTileService();
4411         }
4412         final boolean shouldFilterAppAccess = Binder.getCallingPid() != OWN_PROCESS_ID;
4413         final int callingUid = Binder.getCallingUid();
4414         final PackageManagerInternal pm = LocalServices.getService(
4415                 PackageManagerInternal.class);
4416 
4417         for (Map.Entry<ComponentName, ComponentName> entry :
4418                 a11yFeatureToTileService.entrySet()) {
4419             if (shouldFilterAppAccess
4420                     && pm.filterAppAccess(
4421                     entry.getKey().getPackageName(), callingUid, resolvedUserId)) {
4422                 continue;
4423             }
4424             a11yFeatureToTile.put(entry.getKey(), entry.getValue());
4425         }
4426 
4427         a11yFeatureToTile.putAll(ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE);
4428         return a11yFeatureToTile;
4429     }
4430 
4431     @Override
4432     @EnforcePermission(MANAGE_ACCESSIBILITY)
getAccessibilityShortcutTargets(@serShortcutType int shortcutType)4433     public List<String> getAccessibilityShortcutTargets(@UserShortcutType int shortcutType) {
4434         getAccessibilityShortcutTargets_enforcePermission();
4435         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
4436             mTraceManager.logTrace(LOG_TAG + ".getAccessibilityShortcutTargets",
4437                     FLAGS_ACCESSIBILITY_MANAGER, "shortcutType=" + shortcutType);
4438         }
4439         return getAccessibilityShortcutTargetsInternal(shortcutType);
4440     }
4441 
getAccessibilityShortcutTargetsInternal( @serShortcutType int shortcutType)4442     private List<String> getAccessibilityShortcutTargetsInternal(
4443             @UserShortcutType int shortcutType) {
4444         synchronized (mLock) {
4445             final AccessibilityUserState userState = getCurrentUserStateLocked();
4446             final ArrayList<String> shortcutTargets = new ArrayList<>(
4447                     userState.getShortcutTargetsLocked(shortcutType));
4448             if (shortcutType != UserShortcutType.SOFTWARE) {
4449                 return shortcutTargets;
4450             }
4451             // Adds legacy a11y services requesting a11y button into the list.
4452             for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
4453                 final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
4454                 if (!service.mRequestAccessibilityButton
4455                         || service.getServiceInfo().getResolveInfo().serviceInfo.applicationInfo
4456                         .targetSdkVersion > Build.VERSION_CODES.Q) {
4457                     continue;
4458                 }
4459                 final String serviceName = service.getComponentName().flattenToString();
4460                 if (!TextUtils.isEmpty(serviceName)) {
4461                     shortcutTargets.add(serviceName);
4462                 }
4463             }
4464             return shortcutTargets;
4465         }
4466     }
4467 
4468     /**
4469      * Enables accessibility service specified by {@param componentName} for the {@param userId}.
4470      */
enableAccessibilityServiceLocked(ComponentName componentName, int userId)4471     private void enableAccessibilityServiceLocked(ComponentName componentName, int userId) {
4472         mTempComponentNameSet.clear();
4473         readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
4474                 userId, mTempComponentNameSet);
4475         mTempComponentNameSet.add(componentName);
4476         persistComponentNamesToSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
4477                 mTempComponentNameSet, userId);
4478 
4479         AccessibilityUserState userState = getUserStateLocked(userId);
4480         if (userState.mEnabledServices.add(componentName)) {
4481             onUserStateChangedLocked(userState);
4482         }
4483     }
4484 
4485     /**
4486      * Disables accessibility service specified by {@param componentName} for the {@param userId}.
4487      */
disableAccessibilityServiceLocked(ComponentName componentName, int userId)4488     private void disableAccessibilityServiceLocked(ComponentName componentName, int userId) {
4489         mTempComponentNameSet.clear();
4490         readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
4491                 userId, mTempComponentNameSet);
4492         mTempComponentNameSet.remove(componentName);
4493         persistComponentNamesToSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
4494                 mTempComponentNameSet, userId);
4495 
4496         AccessibilityUserState userState = getUserStateLocked(userId);
4497         if (userState.mEnabledServices.remove(componentName)) {
4498             onUserStateChangedLocked(userState);
4499         }
4500     }
4501 
4502     @Override
sendAccessibilityEventForCurrentUserLocked(AccessibilityEvent event)4503     public void sendAccessibilityEventForCurrentUserLocked(AccessibilityEvent event) {
4504         if (event.getWindowChanges() == AccessibilityEvent.WINDOWS_CHANGE_ADDED) {
4505             // We need to ensure the window is available before sending pending
4506             // window_state_changed events.
4507             sendPendingWindowStateChangedEventsForAvailableWindowLocked(event.getWindowId());
4508         }
4509         sendAccessibilityEventLocked(event, mCurrentUserId);
4510     }
4511 
sendAccessibilityEventLocked(AccessibilityEvent event, int userId)4512     private void sendAccessibilityEventLocked(AccessibilityEvent event, int userId) {
4513         // Resync to avoid calling out with the lock held
4514         event.setEventTime(SystemClock.uptimeMillis());
4515         mMainHandler.sendMessage(obtainMessage(
4516                 AccessibilityManagerService::sendAccessibilityEvent,
4517                 this, event, userId));
4518     }
4519 
4520     /**
4521      * AIDL-exposed method. System only.
4522      * Inform accessibility that a fingerprint gesture was performed
4523      *
4524      * @param gestureKeyCode The key code corresponding to the fingerprint gesture.
4525      * @return {@code true} if accessibility consumes the fingerprint gesture, {@code false} if it
4526      * doesn't.
4527      */
4528     @Override
4529     @RequiresNoPermission
sendFingerprintGesture(int gestureKeyCode)4530     public boolean sendFingerprintGesture(int gestureKeyCode) {
4531         if (mTraceManager.isA11yTracingEnabledForTypes(
4532                 FLAGS_ACCESSIBILITY_MANAGER | FLAGS_FINGERPRINT)) {
4533             mTraceManager.logTrace(LOG_TAG + ".sendFingerprintGesture",
4534                     FLAGS_ACCESSIBILITY_MANAGER | FLAGS_FINGERPRINT,
4535                     "gestureKeyCode=" + gestureKeyCode);
4536         }
4537 
4538         synchronized(mLock) {
4539             if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
4540                 // TODO(b/333547153) remove the AIDL definitions for these functions that are
4541                 // restricted to system server and move them to AccessibilityManagerInternal.
4542                 throw new SecurityException("Only SYSTEM can call sendFingerprintGesture");
4543             }
4544         }
4545         if (mFingerprintGestureDispatcher == null) {
4546             return false;
4547         }
4548         return mFingerprintGestureDispatcher.onFingerprintGesture(gestureKeyCode);
4549     }
4550 
4551     /**
4552      * AIDL-exposed method. System only.
4553      * Gets accessibility window id from window token.
4554      *
4555      * @param windowToken Window token to get accessibility window id.
4556      * @return Accessibility window id for the window token. Returns -1 if no such token is
4557      *   registered.
4558      */
4559     @Override
4560     @RequiresNoPermission
getAccessibilityWindowId(@ullable IBinder windowToken)4561     public int getAccessibilityWindowId(@Nullable IBinder windowToken) {
4562         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
4563             mTraceManager.logTrace(LOG_TAG + ".getAccessibilityWindowId",
4564                     FLAGS_ACCESSIBILITY_MANAGER, "windowToken=" + windowToken);
4565         }
4566 
4567         synchronized (mLock) {
4568             if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
4569                 throw new SecurityException("Only SYSTEM can call getAccessibilityWindowId");
4570             }
4571 
4572             return mA11yWindowManager.findWindowIdLocked(mCurrentUserId, windowToken);
4573         }
4574     }
4575 
4576     /**
4577      * Get the recommended timeout of interactive controls and non-interactive controls.
4578      *
4579      * @return A long for pair of {@code int}s. First integer for interactive one, and second
4580      * integer for non-interactive one.
4581      */
4582     @Override
4583     @RequiresNoPermission
getRecommendedTimeoutMillis()4584     public long getRecommendedTimeoutMillis() {
4585         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
4586             mTraceManager.logTrace(
4587                     LOG_TAG + ".getRecommendedTimeoutMillis", FLAGS_ACCESSIBILITY_MANAGER);
4588         }
4589 
4590         synchronized(mLock) {
4591             final int deviceId = mProxyManager.getFirstDeviceIdForUidLocked(
4592                     Binder.getCallingUid());
4593             if (mProxyManager.isProxyedDeviceId(deviceId)) {
4594                 return mProxyManager.getRecommendedTimeoutMillisLocked(deviceId);
4595             } else {
4596                 final AccessibilityUserState userState = getCurrentUserStateLocked();
4597                 return getRecommendedTimeoutMillisLocked(userState);
4598             }
4599         }
4600     }
4601 
getRecommendedTimeoutMillisLocked(AccessibilityUserState userState)4602     private long getRecommendedTimeoutMillisLocked(AccessibilityUserState userState) {
4603         return IntPair.of(userState.getInteractiveUiTimeoutLocked(),
4604                 userState.getNonInteractiveUiTimeoutLocked());
4605     }
4606 
4607     @Override
4608     @EnforcePermission(STATUS_BAR_SERVICE)
setMagnificationConnection( IMagnificationConnection connection)4609     public void setMagnificationConnection(
4610             IMagnificationConnection connection) throws RemoteException {
4611         setMagnificationConnection_enforcePermission();
4612         if (mTraceManager.isA11yTracingEnabledForTypes(
4613                 FLAGS_ACCESSIBILITY_MANAGER | FLAGS_MAGNIFICATION_CONNECTION)) {
4614             mTraceManager.logTrace(LOG_TAG + ".setMagnificationConnection",
4615                     FLAGS_ACCESSIBILITY_MANAGER | FLAGS_MAGNIFICATION_CONNECTION,
4616                     "connection=" + connection);
4617         }
4618 
4619         getMagnificationConnectionManager().setConnection(connection);
4620 
4621         if (com.android.window.flags.Flags.alwaysDrawMagnificationFullscreenBorder()
4622                 && connection == null
4623                 && mMagnificationController.isFullScreenMagnificationControllerInitialized()) {
4624             // Since the connection does not exist, the system ui cannot provide the border
4625             // implementation for fullscreen magnification. So we call reset to deactivate the
4626             // fullscreen magnification to prevent the magnified but no border situation.
4627             final ArrayList<Display> displays = getValidDisplayList();
4628             for (int i = 0; i < displays.size(); i++) {
4629                 final Display display = displays.get(i);
4630                 getMagnificationController().getFullScreenMagnificationController()
4631                         .reset(display.getDisplayId(), false);
4632             }
4633         }
4634     }
4635 
4636     /**
4637      * Getter of {@link MagnificationConnectionManager}.
4638      *
4639      * @return MagnificationManager
4640      */
getMagnificationConnectionManager()4641     public MagnificationConnectionManager getMagnificationConnectionManager() {
4642         synchronized (mLock) {
4643             return mMagnificationController.getMagnificationConnectionManager();
4644         }
4645     }
4646 
4647     /**
4648      * Getter of {@link MagnificationController}.
4649      *
4650      * @return MagnificationController
4651      */
getMagnificationController()4652     MagnificationController getMagnificationController() {
4653         return mMagnificationController;
4654     }
4655 
4656     @Override
4657     @RequiresNoPermission
associateEmbeddedHierarchy(@onNull IBinder host, @NonNull IBinder embedded)4658     public void associateEmbeddedHierarchy(@NonNull IBinder host, @NonNull IBinder embedded) {
4659         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
4660             mTraceManager.logTrace(LOG_TAG + ".associateEmbeddedHierarchy",
4661                     FLAGS_ACCESSIBILITY_MANAGER, "host=" + host + ";embedded=" + embedded);
4662         }
4663 
4664         synchronized (mLock) {
4665             mA11yWindowManager.associateEmbeddedHierarchyLocked(host, embedded);
4666         }
4667     }
4668 
4669     @Override
4670     @RequiresNoPermission
disassociateEmbeddedHierarchy(@onNull IBinder token)4671     public void disassociateEmbeddedHierarchy(@NonNull IBinder token) {
4672         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
4673             mTraceManager.logTrace(LOG_TAG + ".disassociateEmbeddedHierarchy",
4674                     FLAGS_ACCESSIBILITY_MANAGER, "token=" + token);
4675         }
4676 
4677         synchronized (mLock) {
4678             mA11yWindowManager.disassociateEmbeddedHierarchyLocked(token);
4679         }
4680     }
4681 
4682     /**
4683      * Gets the stroke width of the focus rectangle.
4684      * @return The stroke width.
4685      */
4686     @Override
4687     @RequiresNoPermission
getFocusStrokeWidth()4688     public int getFocusStrokeWidth() {
4689         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
4690             mTraceManager.logTrace(LOG_TAG + ".getFocusStrokeWidth", FLAGS_ACCESSIBILITY_MANAGER);
4691         }
4692         synchronized (mLock) {
4693             final int deviceId = mProxyManager.getFirstDeviceIdForUidLocked(
4694                     Binder.getCallingUid());
4695             if (mProxyManager.isProxyedDeviceId(deviceId)) {
4696                 return mProxyManager.getFocusStrokeWidthLocked(deviceId);
4697             }
4698             final AccessibilityUserState userState = getCurrentUserStateLocked();
4699 
4700             return userState.getFocusStrokeWidthLocked();
4701         }
4702     }
4703 
4704     /**
4705      * Gets the color of the focus rectangle.
4706      * @return The color.
4707      */
4708     @Override
4709     @RequiresNoPermission
getFocusColor()4710     public int getFocusColor() {
4711         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
4712             mTraceManager.logTrace(LOG_TAG + ".getFocusColor", FLAGS_ACCESSIBILITY_MANAGER);
4713         }
4714         synchronized (mLock) {
4715             final int deviceId = mProxyManager.getFirstDeviceIdForUidLocked(
4716                     Binder.getCallingUid());
4717             if (mProxyManager.isProxyedDeviceId(deviceId)) {
4718                 return mProxyManager.getFocusColorLocked(deviceId);
4719             }
4720             final AccessibilityUserState userState = getCurrentUserStateLocked();
4721 
4722             return userState.getFocusColorLocked();
4723         }
4724     }
4725 
4726     /**
4727      * Gets the status of the audio description preference.
4728      * @return {@code true} if the audio description is enabled, {@code false} otherwise.
4729      */
4730     @Override
4731     @RequiresNoPermission
isAudioDescriptionByDefaultEnabled()4732     public boolean isAudioDescriptionByDefaultEnabled() {
4733         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
4734             mTraceManager.logTrace(LOG_TAG + ".isAudioDescriptionByDefaultEnabled",
4735                     FLAGS_ACCESSIBILITY_MANAGER);
4736         }
4737         synchronized (mLock) {
4738             final AccessibilityUserState userState = getCurrentUserStateLocked();
4739 
4740             return userState.isAudioDescriptionByDefaultEnabledLocked();
4741         }
4742     }
4743 
4744     /**
4745      * Sets the {@link AccessibilityWindowAttributes} to the window associated with the given
4746      * window id.
4747      *
4748      * @param displayId The display id of the window.
4749      * @param windowId The id of the window
4750      * @param userId The user id.
4751      * @param attributes The accessibility window attributes.
4752      */
4753     @Override
4754     @RequiresNoPermission
setAccessibilityWindowAttributes(int displayId, int windowId, int userId, AccessibilityWindowAttributes attributes)4755     public void setAccessibilityWindowAttributes(int displayId, int windowId, int userId,
4756             AccessibilityWindowAttributes attributes) {
4757         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
4758             mTraceManager.logTrace(LOG_TAG + ".setAccessibilityWindowAttributes",
4759                     FLAGS_ACCESSIBILITY_MANAGER);
4760         }
4761         mA11yWindowManager.setAccessibilityWindowAttributes(displayId, windowId, userId,
4762                 attributes);
4763     }
4764 
4765     @Override
4766     @EnforcePermission(SET_SYSTEM_AUDIO_CAPTION)
setSystemAudioCaptioningEnabled(boolean isEnabled, int userId)4767     public void setSystemAudioCaptioningEnabled(boolean isEnabled, int userId) {
4768         setSystemAudioCaptioningEnabled_enforcePermission();
4769         mCaptioningManagerImpl.setSystemAudioCaptioningEnabled(isEnabled, userId);
4770     }
4771 
4772     @Override
4773     @RequiresNoPermission
isSystemAudioCaptioningUiEnabled(int userId)4774     public boolean isSystemAudioCaptioningUiEnabled(int userId) {
4775         return mCaptioningManagerImpl.isSystemAudioCaptioningUiEnabled(userId);
4776     }
4777 
4778     @Override
4779     @EnforcePermission(SET_SYSTEM_AUDIO_CAPTION)
setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId)4780     public void setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId) {
4781         setSystemAudioCaptioningUiEnabled_enforcePermission();
4782         mCaptioningManagerImpl.setSystemAudioCaptioningUiEnabled(isEnabled, userId);
4783     }
4784 
4785     @Override
4786     @EnforcePermission(CREATE_VIRTUAL_DEVICE)
registerProxyForDisplay(IAccessibilityServiceClient client, int displayId)4787     public boolean registerProxyForDisplay(IAccessibilityServiceClient client, int displayId)
4788             throws RemoteException {
4789         registerProxyForDisplay_enforcePermission();
4790         mSecurityPolicy.checkForAccessibilityPermissionOrRole();
4791         if (client == null) {
4792             return false;
4793         }
4794         if (displayId < 0) {
4795             throw new IllegalArgumentException("The display id " + displayId + " is invalid.");
4796         }
4797         if (!isTrackedDisplay(displayId)) {
4798             throw new IllegalArgumentException("The display " + displayId + " does not exist or is"
4799                     + " not tracked by accessibility.");
4800         }
4801         if (mProxyManager.isProxyedDisplay(displayId)) {
4802             throw new IllegalArgumentException("The display " + displayId + " is already being"
4803                     + " proxy-ed");
4804         }
4805         if (!mProxyManager.displayBelongsToCaller(Binder.getCallingUid(), displayId)) {
4806             throw new SecurityException("The display " + displayId + " does not belong to"
4807                     + " the caller.");
4808         }
4809 
4810         final long identity = Binder.clearCallingIdentity();
4811         try {
4812             mProxyManager.registerProxy(client, displayId, sIdCounter++, mSecurityPolicy,
4813                     this, getTraceManager(), mWindowManagerService);
4814 
4815             synchronized (mLock) {
4816                 notifyClearAccessibilityCacheLocked();
4817             }
4818         } finally {
4819             Binder.restoreCallingIdentity(identity);
4820         }
4821         return true;
4822     }
4823 
4824     @Override
4825     @EnforcePermission(CREATE_VIRTUAL_DEVICE)
unregisterProxyForDisplay(int displayId)4826     public boolean unregisterProxyForDisplay(int displayId) {
4827         unregisterProxyForDisplay_enforcePermission();
4828         mSecurityPolicy.checkForAccessibilityPermissionOrRole();
4829         final long identity = Binder.clearCallingIdentity();
4830         try {
4831             return mProxyManager.unregisterProxy(displayId);
4832         } finally {
4833             Binder.restoreCallingIdentity(identity);
4834         }
4835     }
4836 
isDisplayProxyed(int displayId)4837     boolean isDisplayProxyed(int displayId) {
4838         return mProxyManager.isProxyedDisplay(displayId);
4839     }
4840 
4841     @Override
4842     @RequiresNoPermission
startFlashNotificationSequence(String opPkg, @FlashNotificationReason int reason, IBinder token)4843     public boolean startFlashNotificationSequence(String opPkg,
4844             @FlashNotificationReason int reason, IBinder token) {
4845         final long identity = Binder.clearCallingIdentity();
4846         try {
4847             return mFlashNotificationsController.startFlashNotificationSequence(opPkg,
4848                     reason, token);
4849         } finally {
4850             Binder.restoreCallingIdentity(identity);
4851         }
4852     }
4853 
4854     @Override
4855     @RequiresNoPermission
stopFlashNotificationSequence(String opPkg)4856     public boolean stopFlashNotificationSequence(String opPkg) {
4857         final long identity = Binder.clearCallingIdentity();
4858         try {
4859             return mFlashNotificationsController.stopFlashNotificationSequence(opPkg);
4860         } finally {
4861             Binder.restoreCallingIdentity(identity);
4862         }
4863     }
4864 
4865     @Override
4866     @RequiresNoPermission
startFlashNotificationEvent(String opPkg, @FlashNotificationReason int reason, String reasonPkg)4867     public boolean startFlashNotificationEvent(String opPkg,
4868             @FlashNotificationReason int reason, String reasonPkg) {
4869         final long identity = Binder.clearCallingIdentity();
4870         try {
4871             return mFlashNotificationsController.startFlashNotificationEvent(opPkg,
4872                     reason, reasonPkg);
4873         } finally {
4874             Binder.restoreCallingIdentity(identity);
4875         }
4876     }
4877 
4878     @Override
4879     @RequiresNoPermission
isAccessibilityTargetAllowed(String packageName, int uid, int userId)4880     public boolean isAccessibilityTargetAllowed(String packageName, int uid, int userId) {
4881         final long identity = Binder.clearCallingIdentity();
4882         try {
4883             final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
4884             final List<String> permittedServices = dpm.getPermittedAccessibilityServices(userId);
4885 
4886             // permittedServices null means all accessibility services are allowed.
4887             boolean allowed = permittedServices == null || permittedServices.contains(packageName);
4888             if (allowed) {
4889                 if (android.permission.flags.Flags.enhancedConfirmationModeApisEnabled()
4890                         && android.security.Flags.extendEcmToAllSettings()) {
4891                     try {
4892                         return !mContext.getSystemService(EnhancedConfirmationManager.class)
4893                                 .isRestricted(packageName,
4894                                         AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE);
4895                     } catch (PackageManager.NameNotFoundException e) {
4896                         Log.e(LOG_TAG, "Exception when retrieving package:" + packageName, e);
4897                         return false;
4898                     }
4899                 } else {
4900                     try {
4901                         final int mode = mContext.getSystemService(AppOpsManager.class)
4902                                 .noteOpNoThrow(AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS,
4903                                         uid, packageName);
4904                         final boolean ecmEnabled = mContext.getResources().getBoolean(
4905                                 com.android.internal.R.bool.config_enhancedConfirmationModeEnabled);
4906                         return !ecmEnabled || mode == AppOpsManager.MODE_ALLOWED
4907                                 || mode == AppOpsManager.MODE_DEFAULT;
4908                     } catch (Exception e) {
4909                         // Fallback in case if app ops is not available in testing.
4910                         return false;
4911                     }
4912                 }
4913             }
4914             return false;
4915         } finally {
4916             Binder.restoreCallingIdentity(identity);
4917         }
4918     }
4919 
4920     @Override
4921     @RequiresNoPermission
sendRestrictedDialogIntent(String packageName, int uid, int userId)4922     public boolean sendRestrictedDialogIntent(String packageName, int uid, int userId) {
4923         // The accessibility service is allowed. Don't show the restricted dialog.
4924         if (isAccessibilityTargetAllowed(packageName, uid, userId)) {
4925             return false;
4926         }
4927 
4928         final EnforcedAdmin admin =
4929                 RestrictedLockUtilsInternal.checkIfAccessibilityServiceDisallowed(
4930                         mContext, packageName, userId);
4931         if (admin != null) {
4932             RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, admin);
4933             return true;
4934         }
4935 
4936         if (android.permission.flags.Flags.enhancedConfirmationModeApisEnabled()
4937                 && android.security.Flags.extendEcmToAllSettings()) {
4938             try {
4939                 Intent settingDialogIntent = mContext
4940                         .getSystemService(EnhancedConfirmationManager.class)
4941                         .createRestrictedSettingDialogIntent(packageName,
4942                                 AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE);
4943                 mContext.startActivity(settingDialogIntent);
4944             } catch (PackageManager.NameNotFoundException e) {
4945                 Log.e(LOG_TAG, "Exception when retrieving package:" + packageName, e);
4946             }
4947         } else {
4948             RestrictedLockUtils.sendShowRestrictedSettingDialogIntent(mContext,
4949                     packageName, uid);
4950         }
4951         return true;
4952     }
4953 
4954     @Override
4955     @EnforcePermission(MANAGE_ACCESSIBILITY)
isAccessibilityServiceWarningRequired(AccessibilityServiceInfo info)4956     public boolean isAccessibilityServiceWarningRequired(AccessibilityServiceInfo info) {
4957         isAccessibilityServiceWarningRequired_enforcePermission();
4958         final ComponentName componentName = info.getComponentName();
4959 
4960         // Warning is not required if the service is already enabled.
4961         synchronized (mLock) {
4962             final AccessibilityUserState userState = getCurrentUserStateLocked();
4963             if (userState.getEnabledServicesLocked().contains(componentName)) {
4964                 return false;
4965             }
4966         }
4967         // Warning is not required if the service is already assigned to a shortcut.
4968         for (int shortcutType : ShortcutConstants.USER_SHORTCUT_TYPES) {
4969             if (getAccessibilityShortcutTargets(shortcutType).contains(
4970                     componentName.flattenToString())) {
4971                 return false;
4972             }
4973         }
4974         // Warning is not required if the service is preinstalled and in the
4975         // trustedAccessibilityServices allowlist.
4976         if (android.view.accessibility.Flags.skipAccessibilityWarningDialogForTrustedServices()
4977                 && isAccessibilityServicePreinstalledAndTrusted(info)) {
4978             return false;
4979         }
4980 
4981         // Warning is required by default.
4982         return true;
4983     }
4984 
isAccessibilityServicePreinstalledAndTrusted(AccessibilityServiceInfo info)4985     private boolean isAccessibilityServicePreinstalledAndTrusted(AccessibilityServiceInfo info) {
4986         final ComponentName componentName = info.getComponentName();
4987         final boolean isPreinstalled =
4988                 info.getResolveInfo().serviceInfo.applicationInfo.isSystemApp();
4989         if (isPreinstalled) {
4990             final String[] trustedAccessibilityServices =
4991                     mContext.getResources().getStringArray(
4992                             R.array.config_trustedAccessibilityServices);
4993             if (Arrays.stream(trustedAccessibilityServices)
4994                     .map(ComponentName::unflattenFromString)
4995                     .anyMatch(componentName::equals)) {
4996                 return true;
4997             }
4998         }
4999         return false;
5000     }
5001 
5002     @Override
5003     @PermissionManuallyEnforced // DUMP
dump(FileDescriptor fd, final PrintWriter pw, String[] args)5004     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
5005         if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
5006         synchronized (mLock) {
5007             pw.println("ACCESSIBILITY MANAGER (dumpsys accessibility)");
5008             pw.println();
5009             pw.append("currentUserId=").append(String.valueOf(mCurrentUserId));
5010             if (mRealCurrentUserId != UserHandle.USER_CURRENT
5011                     && mCurrentUserId != mRealCurrentUserId) {
5012                 pw.append(" (set for UiAutomation purposes; \"real\" current user is ")
5013                         .append(String.valueOf(mRealCurrentUserId)).append(")");
5014             }
5015             pw.println();
5016             if (mVisibleBgUserIds != null) {
5017                 pw.append("visibleBgUserIds=").append(mVisibleBgUserIds.toString());
5018                 pw.println();
5019             }
5020             pw.append("hasMagnificationConnection=").append(
5021                     String.valueOf(getMagnificationConnectionManager().isConnected()));
5022             pw.println();
5023             mMagnificationProcessor.dump(pw, getValidDisplayList());
5024             final int userCount = mUserStates.size();
5025             for (int i = 0; i < userCount; i++) {
5026                 mUserStates.valueAt(i).dump(fd, pw, args);
5027             }
5028             if (mUiAutomationManager.isUiAutomationRunningLocked()) {
5029                 mUiAutomationManager.dumpUiAutomationService(fd, pw, args);
5030                 pw.println();
5031             }
5032             mA11yWindowManager.dump(fd, pw, args);
5033             if (mHasInputFilter && mInputFilter != null) {
5034                 mInputFilter.dump(fd, pw, args);
5035             }
5036             pw.println("Global client list info:{");
5037             mGlobalClients.dump(pw, "    Client list ");
5038             pw.println("    Registered clients:{");
5039             for (int i = 0; i < mGlobalClients.getRegisteredCallbackCount(); i++) {
5040                 AccessibilityManagerService.Client client = (AccessibilityManagerService.Client)
5041                         mGlobalClients.getRegisteredCallbackCookie(i);
5042                 pw.append(Arrays.toString(client.mPackageNames));
5043             }
5044             pw.println();
5045             mProxyManager.dump(fd, pw, args);
5046             mA11yDisplayListener.dump(fd, pw, args);
5047         }
5048     }
5049 
5050     //TODO remove after refactoring KeyEventDispatcherTest
5051     final class MainHandler extends Handler {
5052         public static final int MSG_SEND_KEY_EVENT_TO_INPUT_FILTER = 8;
5053 
MainHandler(Looper looper)5054         public MainHandler(Looper looper) {
5055             super(looper);
5056         }
5057 
5058         @Override
handleMessage(Message msg)5059         public void handleMessage(Message msg) {
5060             if (msg.what == MSG_SEND_KEY_EVENT_TO_INPUT_FILTER) {
5061                 KeyEvent event = (KeyEvent) msg.obj;
5062                 final int policyFlags = msg.arg1;
5063                 synchronized (mLock) {
5064                     if (mHasInputFilter && mInputFilter != null) {
5065                         mInputFilter.sendInputEvent(event, policyFlags);
5066                     }
5067                 }
5068                 event.recycle();
5069             }
5070         }
5071     }
5072 
5073     @Override
getMagnificationProcessor()5074     public MagnificationProcessor getMagnificationProcessor() {
5075         return mMagnificationProcessor;
5076     }
5077 
5078     @Override
onClientChangeLocked(boolean serviceInfoChanged)5079     public void onClientChangeLocked(boolean serviceInfoChanged) {
5080         onClientChangeLocked(serviceInfoChanged, false);
5081     }
5082 
5083     /**
5084      * Called when the state of a service or proxy has changed
5085      * @param serviceInfoChanged if the service info has changed
5086      * @param forceUpdate whether to force an update of state for app clients
5087      */
onClientChangeLocked(boolean serviceInfoChanged, boolean forceUpdate)5088     public void onClientChangeLocked(boolean serviceInfoChanged, boolean forceUpdate) {
5089         AccessibilityUserState userState = getUserStateLocked(mCurrentUserId);
5090         onUserStateChangedLocked(userState, forceUpdate);
5091         if (serviceInfoChanged) {
5092             scheduleNotifyClientsOfServicesStateChangeLocked(userState);
5093         }
5094     }
5095 
5096 
5097     @Override
onProxyChanged(int deviceId)5098     public void onProxyChanged(int deviceId) {
5099         mProxyManager.onProxyChanged(deviceId);
5100     }
5101 
5102     /**
5103      * Removes the device from tracking. This will reset any AccessibilityManagerClients to be
5104      * associated with the default user id.
5105      */
5106     @Override
removeDeviceIdLocked(int deviceId)5107     public void removeDeviceIdLocked(int deviceId) {
5108         resetClientsLocked(deviceId, getCurrentUserStateLocked().mUserClients);
5109         resetClientsLocked(deviceId, mGlobalClients);
5110         // Force an update of A11yManagers if the state was previously a proxy state and needs to be
5111         // returned to the default device state.
5112         onClientChangeLocked(true, true);
5113     }
5114 
resetClientsLocked(int deviceId, RemoteCallbackList<IAccessibilityManagerClient> clients)5115     private void resetClientsLocked(int deviceId,
5116             RemoteCallbackList<IAccessibilityManagerClient> clients) {
5117         if (clients == null || clients.getRegisteredCallbackCount() == 0) {
5118             return;
5119         }
5120         synchronized (mLock) {
5121             for (int i = 0; i < clients.getRegisteredCallbackCount(); i++) {
5122                 final Client appClient = ((Client) clients.getRegisteredCallbackCookie(i));
5123                 if (appClient.mDeviceId == deviceId) {
5124                     appClient.mDeviceId = DEVICE_ID_DEFAULT;
5125                 }
5126             }
5127         }
5128     }
5129 
5130     @Override
updateWindowsForAccessibilityCallbackLocked()5131     public void updateWindowsForAccessibilityCallbackLocked() {
5132         updateWindowsForAccessibilityCallbackLocked(getUserStateLocked(mCurrentUserId));
5133     }
5134 
5135     @Override
getGlobalClientsLocked()5136     public RemoteCallbackList<IAccessibilityManagerClient> getGlobalClientsLocked() {
5137         return mGlobalClients;
5138     }
5139 
5140     @Override
getCurrentUserClientsLocked()5141     public RemoteCallbackList<IAccessibilityManagerClient> getCurrentUserClientsLocked() {
5142         return getCurrentUserState().mUserClients;
5143     }
5144 
5145     @Override
5146     @RequiresNoPermission
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)5147     public void onShellCommand(FileDescriptor in, FileDescriptor out,
5148             FileDescriptor err, String[] args, ShellCallback callback,
5149             ResultReceiver resultReceiver) {
5150         new AccessibilityShellCommand(mContext, this, mSystemActionPerformer)
5151                 .exec(this, in, out, err, args, callback, resultReceiver);
5152     }
5153 
5154     private final class InteractionBridge {
5155         private final ComponentName COMPONENT_NAME =
5156                 new ComponentName("com.android.server.accessibility", "InteractionBridge");
5157 
5158         private final Display mDefaultDisplay;
5159         private final int mConnectionId;
5160         private final AccessibilityInteractionClient mClient;
5161 
InteractionBridge()5162         public InteractionBridge() {
5163             final AccessibilityServiceInfo info = new AccessibilityServiceInfo();
5164             info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
5165             info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
5166             info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
5167             info.setAccessibilityTool(true);
5168             final AccessibilityUserState userState;
5169             synchronized (mLock) {
5170                 userState = getCurrentUserStateLocked();
5171             }
5172             AccessibilityServiceConnection service = new AccessibilityServiceConnection(
5173                     userState, mContext,
5174                     COMPONENT_NAME, info, sIdCounter++, mMainHandler, mLock, mSecurityPolicy,
5175                     AccessibilityManagerService.this,
5176                     AccessibilityManagerService.this.getTraceManager(), mWindowManagerService,
5177                     getSystemActionPerformer(), mA11yWindowManager, mActivityTaskManagerService) {
5178                 @Override
5179                 public boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) {
5180                     return true;
5181                 }
5182             };
5183 
5184             mConnectionId = service.mId;
5185 
5186             mClient = AccessibilityInteractionClient.getInstance(mContext);
5187             mClient.addConnection(mConnectionId, service, /*initializeCache=*/false);
5188 
5189             //TODO: (multi-display) We need to support multiple displays.
5190             DisplayManager displayManager = (DisplayManager)
5191                     mContext.getSystemService(Context.DISPLAY_SERVICE);
5192             mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
5193         }
5194 
5195         /**
5196          * Gets a point within the accessibility focused node where we can send down and up events
5197          * to perform a click.
5198          *
5199          * @param outPoint The click point to populate.
5200          * @return Whether accessibility a click point was found and set.
5201          */
5202         // TODO: (multi-display) Make sure this works for multiple displays.
getAccessibilityFocusClickPointInScreen(Point outPoint)5203         boolean getAccessibilityFocusClickPointInScreen(Point outPoint) {
5204             return getInteractionBridge()
5205                     .getAccessibilityFocusClickPointInScreenNotLocked(outPoint);
5206         }
5207 
5208     /**
5209          * Perform an accessibility action on the view that currently has accessibility focus.
5210          * Has no effect if no item has accessibility focus, if the item with accessibility
5211          * focus does not expose the specified action, or if the action fails.
5212          *
5213          * @param action The action to perform.
5214          *
5215          * @return {@code true} if the action was performed. {@code false} if it was not.
5216          */
performActionOnAccessibilityFocusedItemNotLocked( AccessibilityNodeInfo.AccessibilityAction action)5217         public boolean performActionOnAccessibilityFocusedItemNotLocked(
5218                 AccessibilityNodeInfo.AccessibilityAction action) {
5219             AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked();
5220             if ((focus == null) || !focus.getActionList().contains(action)) {
5221                 return false;
5222             }
5223             return focus.performAction(action.getId());
5224         }
5225 
getAccessibilityFocusClickPointInScreenNotLocked(Point outPoint)5226         public boolean getAccessibilityFocusClickPointInScreenNotLocked(Point outPoint) {
5227             AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked();
5228             if (focus == null) {
5229                 return false;
5230             }
5231 
5232             synchronized (mLock) {
5233                 Rect boundsInScreenBeforeMagnification = mTempRect;
5234 
5235                 focus.getBoundsInScreen(boundsInScreenBeforeMagnification);
5236                 final Point nodeCenter = new Point(boundsInScreenBeforeMagnification.centerX(),
5237                         boundsInScreenBeforeMagnification.centerY());
5238 
5239                 // Invert magnification if needed.
5240                 final Pair<float[], MagnificationSpec> pair =
5241                         getWindowTransformationMatrixAndMagnificationSpec(focus.getWindowId());
5242                 MagnificationSpec spec = null;
5243                 if (pair != null && pair.second != null) {
5244                     spec = new MagnificationSpec();
5245                     spec.setTo(pair.second);
5246                 }
5247 
5248                 if (spec != null && !spec.isNop()) {
5249                     boundsInScreenBeforeMagnification.offset((int) -spec.offsetX,
5250                             (int) -spec.offsetY);
5251                     boundsInScreenBeforeMagnification.scale(1 / spec.scale);
5252                 }
5253 
5254                 //Clip to the window bounds.
5255                 Rect windowBounds = mTempRect1;
5256                 AccessibilityWindowInfo window = focus.getWindow();
5257                 if (window != null) {
5258                     window.getBoundsInScreen(windowBounds);
5259                 }
5260                 if (!boundsInScreenBeforeMagnification.intersect(windowBounds)) {
5261                     return false;
5262                 }
5263 
5264                 //Clip to the screen bounds.
5265                 Point screenSize = mTempPoint;
5266                 mDefaultDisplay.getRealSize(screenSize);
5267                 if (!boundsInScreenBeforeMagnification.intersect(0, 0, screenSize.x,
5268                         screenSize.y)) {
5269                     return false;
5270                 }
5271 
5272                 outPoint.set(nodeCenter.x, nodeCenter.y);
5273             }
5274 
5275             return true;
5276         }
5277 
getAccessibilityFocusNotLocked()5278         private AccessibilityNodeInfo getAccessibilityFocusNotLocked() {
5279             final int focusedWindowId;
5280             synchronized (mLock) {
5281                 focusedWindowId = mA11yWindowManager.getFocusedWindowId(
5282                         AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
5283                 if (focusedWindowId == AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
5284                     return null;
5285                 }
5286             }
5287             return getAccessibilityFocusNotLocked(focusedWindowId);
5288         }
5289 
getAccessibilityFocusNotLocked(int windowId)5290         private AccessibilityNodeInfo getAccessibilityFocusNotLocked(int windowId) {
5291             return mClient.findFocus(mConnectionId,
5292                     windowId, AccessibilityNodeInfo.ROOT_NODE_ID,
5293                     AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
5294         }
5295     }
5296 
5297     /**
5298      * Gets all currently valid logical displays.
5299      *
5300      * @return An array list containing all valid logical displays.
5301      */
getValidDisplayList()5302     public ArrayList<Display> getValidDisplayList() {
5303         return mA11yDisplayListener.getValidDisplayList();
5304     }
5305 
5306 
5307     /**
5308      *  Returns {@code true} if the display id is in the list of currently valid logical displays
5309      *  being tracked by a11y.
5310      */
isTrackedDisplay(int displayId)5311     private boolean isTrackedDisplay(int displayId) {
5312         final ArrayList<Display> displays = getValidDisplayList();
5313         for (Display display : displays) {
5314             if (display.getDisplayId() == displayId) {
5315                 return true;
5316             }
5317         }
5318         return false;
5319     }
5320 
5321     /**
5322      * A Utility class to handle display state.
5323      */
5324     public class AccessibilityDisplayListener implements DisplayManager.DisplayListener {
5325         private final DisplayManager mDisplayManager;
5326         private final ArrayList<Display> mDisplaysList = new ArrayList<>();
5327         private int mSystemUiUid = 0;
5328 
AccessibilityDisplayListener(Context context, Handler handler)5329         AccessibilityDisplayListener(Context context, Handler handler) {
5330             // Avoid concerns about one thread adding displays while another thread removes
5331             // them by ensuring the looper is the main looper and the DisplayListener
5332             // callbacks are always executed on the one main thread.
5333             final boolean isMainHandler = handler.getLooper() == Looper.getMainLooper();
5334             final String errorMessage =
5335                     "AccessibilityDisplayListener must use the main handler";
5336             if (Build.IS_USERDEBUG || Build.IS_ENG) {
5337                 Preconditions.checkArgument(isMainHandler, errorMessage);
5338             } else if (!isMainHandler) {
5339                 Slog.e(LOG_TAG, errorMessage);
5340             }
5341 
5342             mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
5343             mDisplayManager.registerDisplayListener(this, handler);
5344             initializeDisplayList();
5345 
5346             final PackageManagerInternal pm =
5347                     LocalServices.getService(PackageManagerInternal.class);
5348             if (pm != null) {
5349                 mSystemUiUid = pm.getPackageUid(pm.getSystemUiServiceComponent().getPackageName(),
5350                         PackageManager.MATCH_SYSTEM_ONLY, mCurrentUserId);
5351             }
5352         }
5353 
5354         /**
5355          * Gets all currently valid logical displays.
5356          *
5357          * @return An array list containing all valid logical displays.
5358          */
getValidDisplayList()5359         public ArrayList<Display> getValidDisplayList() {
5360             synchronized (mLock) {
5361                 return mDisplaysList;
5362             }
5363         }
5364 
initializeDisplayList()5365         private void initializeDisplayList() {
5366             final Display[] displays = mDisplayManager.getDisplays();
5367             synchronized (mLock) {
5368                 mDisplaysList.clear();
5369                 for (int i = 0; i < displays.length; i++) {
5370                     // Exclude overlay virtual displays. The display list is for A11yInputFilter
5371                     // to create event handler per display. The events should be handled by the
5372                     // display which is overlaid by it.
5373                     final Display display = displays[i];
5374                     if (isValidDisplay(display)) {
5375                         mDisplaysList.add(display);
5376                     }
5377                 }
5378             }
5379         }
5380 
5381         @Override
onDisplayAdded(int displayId)5382         public void onDisplayAdded(int displayId) {
5383             final boolean isMainThread = Looper.getMainLooper().isCurrentThread();
5384             final String errorMessage = "onDisplayAdded must be called from the main thread";
5385             if (Build.IS_USERDEBUG || Build.IS_ENG) {
5386                 Preconditions.checkArgument(isMainThread, errorMessage);
5387             } else if (!isMainThread) {
5388                 Slog.e(LOG_TAG, errorMessage);
5389             }
5390             final Display display = mDisplayManager.getDisplay(displayId);
5391             if (!isValidDisplay(display)) {
5392                 return;
5393             }
5394 
5395             final List<AccessibilityServiceConnection> services;
5396             synchronized (mLock) {
5397                 mDisplaysList.add(display);
5398                 mA11yOverlayLayers.put(
5399                         displayId, mWindowManagerService.getA11yOverlayLayer(displayId));
5400                 if (mInputFilter != null) {
5401                     mInputFilter.onDisplayAdded(display);
5402                 }
5403                 AccessibilityUserState userState = getCurrentUserStateLocked();
5404                 services = new ArrayList<>(userState.mBoundServices);
5405                 updateMagnificationLocked(userState);
5406                 updateWindowsForAccessibilityCallbackLocked(userState);
5407                 notifyClearAccessibilityCacheLocked();
5408             }
5409             if (displayId != Display.DEFAULT_DISPLAY) {
5410                 for (int i = 0; i < services.size(); i++) {
5411                     AccessibilityServiceConnection boundClient = services.get(i);
5412                     boundClient.addWindowTokenForDisplay(displayId);
5413                 }
5414             }
5415         }
5416 
5417         @Override
onDisplayRemoved(int displayId)5418         public void onDisplayRemoved(int displayId) {
5419             final boolean isMainThread = Looper.getMainLooper().isCurrentThread();
5420             final String errorMessage = "onDisplayRemoved must be called from the main thread";
5421             if (Build.IS_USERDEBUG || Build.IS_ENG) {
5422                 Preconditions.checkArgument(isMainThread, errorMessage);
5423             } else if (!isMainThread) {
5424                 Slog.e(LOG_TAG, errorMessage);
5425             }
5426             synchronized (mLock) {
5427                 if (!removeDisplayFromList(displayId)) {
5428                     return;
5429                 }
5430                 mA11yOverlayLayers.remove(displayId);
5431                 if (mInputFilter != null) {
5432                     mInputFilter.onDisplayRemoved(displayId);
5433                 }
5434                 AccessibilityUserState userState = getCurrentUserStateLocked();
5435                 if (displayId != Display.DEFAULT_DISPLAY) {
5436                     final List<AccessibilityServiceConnection> services = userState.mBoundServices;
5437                     for (int i = 0; i < services.size(); i++) {
5438                         AccessibilityServiceConnection boundClient = services.get(i);
5439                         boundClient.onDisplayRemoved(displayId);
5440                     }
5441                 }
5442             }
5443             mMagnificationController.onDisplayRemoved(displayId);
5444             mA11yWindowManager.stopTrackingWindows(displayId);
5445         }
5446 
5447         @GuardedBy("mLock")
removeDisplayFromList(int displayId)5448         private boolean removeDisplayFromList(int displayId) {
5449             for (int i = 0; i < mDisplaysList.size(); i++) {
5450                 if (mDisplaysList.get(i).getDisplayId() == displayId) {
5451                     mDisplaysList.remove(i);
5452                     return true;
5453                 }
5454             }
5455             return false;
5456         }
5457 
5458         @Override
onDisplayChanged(int displayId)5459         public void onDisplayChanged(int displayId) {
5460             /* do nothing */
5461         }
5462 
dump(FileDescriptor fd, PrintWriter pw, String[] args)5463         void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
5464             pw.println("Accessibility Display Listener:");
5465             pw.println("    SystemUI uid: " + mSystemUiUid);
5466             int size = mDisplaysList.size();
5467             pw.printf("    %d valid display%s: ", size, (size == 1 ? "" : "s"));
5468             for (int i = 0; i < size; i++) {
5469                 pw.print(mDisplaysList.get(i).getDisplayId());
5470                 if (i < size - 1) {
5471                     pw.print(", ");
5472                 }
5473             }
5474             pw.println();
5475         }
5476 
isValidDisplay(@ullable Display display)5477         private boolean isValidDisplay(@Nullable Display display) {
5478             if (display == null || display.getType() == Display.TYPE_OVERLAY) {
5479                 return false;
5480             }
5481             // Private virtual displays are created by the ap and is not allowed to access by other
5482             // aps. We assume we could ignore them.
5483             // The exceptional case is for bubbles. Because the bubbles use the activityView, and
5484             // the virtual display of the activityView is private, so if the owner UID of the
5485             // private virtual display is the one of system ui which creates the virtual display of
5486             // bubbles, then this private virtual display should track the windows.
5487             if (display.getType() == Display.TYPE_VIRTUAL
5488                     && (display.getFlags() & Display.FLAG_PRIVATE) != 0
5489                     && display.getOwnerUid() != mSystemUiUid) {
5490                 return false;
5491             }
5492             return true;
5493         }
5494     }
5495 
5496     /** Represents an {@link AccessibilityManager} */
5497     class Client {
5498         final IAccessibilityManagerClient mCallback;
5499         final String[] mPackageNames;
5500         int mLastSentRelevantEventTypes;
5501         int mUid;
5502         int mDeviceId = DEVICE_ID_DEFAULT;
5503 
Client(IAccessibilityManagerClient callback, int clientUid, AccessibilityUserState userState, int deviceId)5504         private Client(IAccessibilityManagerClient callback, int clientUid,
5505                 AccessibilityUserState userState, int deviceId) {
5506             mCallback = callback;
5507             mPackageNames = mPackageManager.getPackagesForUid(clientUid);
5508             mUid = clientUid;
5509             mDeviceId = deviceId;
5510             synchronized (mLock) {
5511                 if (mProxyManager.isProxyedDeviceId(deviceId)) {
5512                     mLastSentRelevantEventTypes =
5513                             mProxyManager.computeRelevantEventTypesLocked(this);
5514                 } else {
5515                     mLastSentRelevantEventTypes = computeRelevantEventTypesLocked(userState, this);
5516                 }
5517             }
5518         }
5519     }
5520 
5521     private final class AccessibilityContentObserver extends ContentObserver {
5522 
5523         private final Uri mTouchExplorationEnabledUri = Settings.Secure.getUriFor(
5524                 Settings.Secure.TOUCH_EXPLORATION_ENABLED);
5525 
5526         private final Uri mMagnificationmSingleFingerTripleTapEnabledUri = Settings.Secure
5527                 .getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
5528 
5529         private final Uri mMagnificationTwoFingerTripleTapEnabledUri = Settings.Secure.getUriFor(
5530                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED);
5531 
5532         private final Uri mAutoclickEnabledUri = Settings.Secure.getUriFor(
5533                 Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED);
5534 
5535         private final Uri mEnabledAccessibilityServicesUri = Settings.Secure.getUriFor(
5536                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
5537 
5538         private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure
5539                 .getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
5540 
5541         private final Uri mHighTextContrastUri = Settings.Secure.getUriFor(
5542                 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED);
5543 
5544         private final Uri mAudioDescriptionByDefaultUri = Settings.Secure.getUriFor(
5545                 Settings.Secure.ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT);
5546 
5547         private final Uri mAccessibilitySoftKeyboardModeUri = Settings.Secure.getUriFor(
5548                 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
5549 
5550         private final Uri mShowImeWithHardKeyboardUri = Settings.Secure.getUriFor(
5551                 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
5552 
5553         private final Uri mAccessibilityShortcutServiceIdUri = Settings.Secure.getUriFor(
5554                 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
5555 
5556         private final Uri mAccessibilityButtonComponentIdUri = Settings.Secure.getUriFor(
5557                 Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT);
5558 
5559         private final Uri mAccessibilityButtonTargetsUri = Settings.Secure.getUriFor(
5560                 Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
5561 
5562         private final Uri mUserNonInteractiveUiTimeoutUri = Settings.Secure.getUriFor(
5563                 Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS);
5564 
5565         private final Uri mUserInteractiveUiTimeoutUri = Settings.Secure.getUriFor(
5566                 Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS);
5567 
5568         private final Uri mMagnificationModeUri = Settings.Secure.getUriFor(
5569                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE);
5570 
5571         private final Uri mMagnificationCapabilityUri = Settings.Secure.getUriFor(
5572                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY);
5573 
5574         private final Uri mMagnificationFollowTypingUri = Settings.Secure.getUriFor(
5575                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED);
5576 
5577         private final Uri mAlwaysOnMagnificationUri = Settings.Secure.getUriFor(
5578                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED);
5579 
AccessibilityContentObserver(Handler handler)5580         public AccessibilityContentObserver(Handler handler) {
5581             super(handler);
5582         }
5583 
register(ContentResolver contentResolver)5584         public void register(ContentResolver contentResolver) {
5585             contentResolver.registerContentObserver(mTouchExplorationEnabledUri,
5586                     false, this, UserHandle.USER_ALL);
5587             contentResolver.registerContentObserver(mMagnificationmSingleFingerTripleTapEnabledUri,
5588                     false, this, UserHandle.USER_ALL);
5589             if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) {
5590                 contentResolver.registerContentObserver(mMagnificationTwoFingerTripleTapEnabledUri,
5591                         false, this, UserHandle.USER_ALL);
5592             }
5593             contentResolver.registerContentObserver(mAutoclickEnabledUri,
5594                     false, this, UserHandle.USER_ALL);
5595             contentResolver.registerContentObserver(mEnabledAccessibilityServicesUri,
5596                     false, this, UserHandle.USER_ALL);
5597             contentResolver.registerContentObserver(
5598                     mTouchExplorationGrantedAccessibilityServicesUri,
5599                     false, this, UserHandle.USER_ALL);
5600             contentResolver.registerContentObserver(
5601                     mHighTextContrastUri, false, this, UserHandle.USER_ALL);
5602             contentResolver.registerContentObserver(
5603                     mAudioDescriptionByDefaultUri, false, this, UserHandle.USER_ALL);
5604             contentResolver.registerContentObserver(
5605                     mAccessibilitySoftKeyboardModeUri, false, this, UserHandle.USER_ALL);
5606             contentResolver.registerContentObserver(
5607                     mShowImeWithHardKeyboardUri, false, this, UserHandle.USER_ALL);
5608             contentResolver.registerContentObserver(
5609                     mAccessibilityShortcutServiceIdUri, false, this, UserHandle.USER_ALL);
5610             contentResolver.registerContentObserver(
5611                     mAccessibilityButtonComponentIdUri, false, this, UserHandle.USER_ALL);
5612             contentResolver.registerContentObserver(
5613                     mAccessibilityButtonTargetsUri, false, this, UserHandle.USER_ALL);
5614             contentResolver.registerContentObserver(
5615                     mUserNonInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL);
5616             contentResolver.registerContentObserver(
5617                     mUserInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL);
5618             contentResolver.registerContentObserver(
5619                     mMagnificationModeUri, false, this, UserHandle.USER_ALL);
5620             contentResolver.registerContentObserver(
5621                     mMagnificationCapabilityUri, false, this, UserHandle.USER_ALL);
5622             contentResolver.registerContentObserver(
5623                     mMagnificationFollowTypingUri, false, this, UserHandle.USER_ALL);
5624             contentResolver.registerContentObserver(
5625                     mAlwaysOnMagnificationUri, false, this, UserHandle.USER_ALL);
5626         }
5627 
5628         @Override
onChange(boolean selfChange, Uri uri)5629         public void onChange(boolean selfChange, Uri uri) {
5630             synchronized (mLock) {
5631                 // Profiles share the accessibility state of the parent. Therefore,
5632                 // we are checking for changes only the parent settings.
5633                 AccessibilityUserState userState = getCurrentUserStateLocked();
5634 
5635                 if (mTouchExplorationEnabledUri.equals(uri)) {
5636                     if (readTouchExplorationEnabledSettingLocked(userState)) {
5637                         onUserStateChangedLocked(userState);
5638                     }
5639                 } else if (mMagnificationmSingleFingerTripleTapEnabledUri.equals(uri)) {
5640                     if (readMagnificationEnabledSettingsLocked(userState)) {
5641                         onUserStateChangedLocked(userState);
5642                     }
5643                 } else if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()
5644                         && mMagnificationTwoFingerTripleTapEnabledUri.equals(uri)) {
5645                     if (readMagnificationTwoFingerTripleTapSettingsLocked(userState)) {
5646                         onUserStateChangedLocked(userState);
5647                     }
5648                 } else if (mAutoclickEnabledUri.equals(uri)) {
5649                     if (readAutoclickEnabledSettingLocked(userState)) {
5650                         onUserStateChangedLocked(userState);
5651                     }
5652                 } else if (mEnabledAccessibilityServicesUri.equals(uri)) {
5653                     if (readEnabledAccessibilityServicesLocked(userState)) {
5654                         mSecurityPolicy.onEnabledServicesChangedLocked(userState.mUserId,
5655                                 userState.mEnabledServices);
5656                         userState.removeDisabledServicesFromTemporaryStatesLocked();
5657                         onUserStateChangedLocked(userState);
5658                     }
5659                 } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) {
5660                     if (readTouchExplorationGrantedAccessibilityServicesLocked(userState)) {
5661                         onUserStateChangedLocked(userState);
5662                     }
5663                 } else if (mHighTextContrastUri.equals(uri)) {
5664                     if (readHighTextContrastEnabledSettingLocked(userState)) {
5665                         onUserStateChangedLocked(userState);
5666                     }
5667                 } else if (mAudioDescriptionByDefaultUri.equals(uri)) {
5668                     if (readAudioDescriptionEnabledSettingLocked(userState)) {
5669                         onUserStateChangedLocked(userState);
5670                     }
5671                 } else if (mAccessibilitySoftKeyboardModeUri.equals(uri)
5672                         || mShowImeWithHardKeyboardUri.equals(uri)) {
5673                     userState.reconcileSoftKeyboardModeWithSettingsLocked();
5674                 } else if (mAccessibilityShortcutServiceIdUri.equals(uri)) {
5675                     if (readAccessibilityShortcutKeySettingLocked(userState)) {
5676                         onUserStateChangedLocked(userState);
5677                     }
5678                 } else if (mAccessibilityButtonComponentIdUri.equals(uri)) {
5679                     if (readAccessibilityButtonTargetComponentLocked(userState)) {
5680                         onUserStateChangedLocked(userState);
5681                     }
5682                 } else if (mAccessibilityButtonTargetsUri.equals(uri)) {
5683                     if (readAccessibilityButtonTargetsLocked(userState)) {
5684                         onUserStateChangedLocked(userState);
5685                     }
5686                 } else if (mUserNonInteractiveUiTimeoutUri.equals(uri)
5687                         || mUserInteractiveUiTimeoutUri.equals(uri)) {
5688                     readUserRecommendedUiTimeoutSettingsLocked(userState);
5689                 } else if (mMagnificationModeUri.equals(uri)) {
5690                     if (readMagnificationModeForDefaultDisplayLocked(userState)) {
5691                         updateMagnificationModeChangeSettingsLocked(userState,
5692                                 Display.DEFAULT_DISPLAY);
5693                     }
5694                 } else if (mMagnificationCapabilityUri.equals(uri)) {
5695                     if (readMagnificationCapabilitiesLocked(userState)) {
5696                         updateMagnificationCapabilitiesSettingsChangeLocked(userState);
5697                     }
5698                 } else if (mMagnificationFollowTypingUri.equals(uri)) {
5699                     readMagnificationFollowTypingLocked(userState);
5700                 } else if (mAlwaysOnMagnificationUri.equals(uri)) {
5701                     readAlwaysOnMagnificationLocked(userState);
5702                 }
5703             }
5704         }
5705     }
5706 
updateMagnificationCapabilitiesSettingsChangeLocked( AccessibilityUserState userState)5707     private void updateMagnificationCapabilitiesSettingsChangeLocked(
5708             AccessibilityUserState userState) {
5709         final ArrayList<Display> displays = getValidDisplayList();
5710         for (int i = 0; i < displays.size(); i++) {
5711             final int displayId = displays.get(i).getDisplayId();
5712             if (fallBackMagnificationModeSettingsLocked(userState, displayId)) {
5713                 updateMagnificationModeChangeSettingsLocked(userState, displayId);
5714             }
5715         }
5716         updateMagnificationConnectionIfNeeded(userState);
5717         // Remove magnification button UI when the magnification capability is not all mode or
5718         // magnification is disabled.
5719         if (!(userState.isMagnificationSingleFingerTripleTapEnabledLocked()
5720                 || (Flags.enableMagnificationMultipleFingerMultipleTapGesture()
5721                 && userState.isMagnificationTwoFingerTripleTapEnabledLocked())
5722                 || userState.isShortcutMagnificationEnabledLocked())
5723                 || userState.getMagnificationCapabilitiesLocked()
5724                 != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) {
5725 
5726             for (int i = 0; i < displays.size(); i++) {
5727                 final int displayId = displays.get(i).getDisplayId();
5728                 getMagnificationConnectionManager().removeMagnificationButton(displayId);
5729             }
5730         }
5731     }
5732 
fallBackMagnificationModeSettingsLocked(AccessibilityUserState userState, int displayId)5733     private boolean fallBackMagnificationModeSettingsLocked(AccessibilityUserState userState,
5734             int displayId) {
5735         if (userState.isValidMagnificationModeLocked(displayId)) {
5736             return false;
5737         }
5738         Slog.w(LOG_TAG, "displayId " + displayId + ", invalid magnification mode:"
5739                 + userState.getMagnificationModeLocked(displayId));
5740         final int capabilities = userState.getMagnificationCapabilitiesLocked();
5741         userState.setMagnificationModeLocked(displayId, capabilities);
5742         if (displayId == Display.DEFAULT_DISPLAY) {
5743             persistMagnificationModeSettingsLocked(capabilities);
5744         }
5745         return true;
5746     }
5747 
persistMagnificationModeSettingsLocked(int mode)5748     private void persistMagnificationModeSettingsLocked(int mode) {
5749         BackgroundThread.getHandler().post(() -> {
5750             final long identity = Binder.clearCallingIdentity();
5751             try {
5752                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
5753                         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, mode, mCurrentUserId);
5754             } finally {
5755                 Binder.restoreCallingIdentity(identity);
5756             }
5757         });
5758     }
5759 
5760     /**
5761      * Gets the magnification mode of the specified display.
5762      *
5763      * @param displayId The logical displayId.
5764      * @return magnification mode. It's either ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN or
5765      * ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW.
5766      */
getMagnificationMode(int displayId)5767     public int getMagnificationMode(int displayId) {
5768         synchronized (mLock) {
5769             return getCurrentUserStateLocked().getMagnificationModeLocked(displayId);
5770         }
5771     }
5772 
5773     // Only the value of the default display is from user settings because not each of displays has
5774     // a unique id.
readMagnificationModeForDefaultDisplayLocked(AccessibilityUserState userState)5775     private boolean readMagnificationModeForDefaultDisplayLocked(AccessibilityUserState userState) {
5776         final int magnificationMode = Settings.Secure.getIntForUser(
5777                 mContext.getContentResolver(),
5778                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE,
5779                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, userState.mUserId);
5780         if (magnificationMode != userState.getMagnificationModeLocked(Display.DEFAULT_DISPLAY)) {
5781             userState.setMagnificationModeLocked(Display.DEFAULT_DISPLAY, magnificationMode);
5782             return true;
5783         }
5784         return false;
5785     }
5786 
readMagnificationCapabilitiesLocked(AccessibilityUserState userState)5787     private boolean readMagnificationCapabilitiesLocked(AccessibilityUserState userState) {
5788         final int capabilities = Settings.Secure.getIntForUser(
5789                 mContext.getContentResolver(),
5790                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY,
5791                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, userState.mUserId);
5792         if (capabilities != userState.getMagnificationCapabilitiesLocked()) {
5793             userState.setMagnificationCapabilitiesLocked(capabilities);
5794             mMagnificationController.setMagnificationCapabilities(capabilities);
5795             return true;
5796         }
5797         return false;
5798     }
5799 
readMagnificationFollowTypingLocked(AccessibilityUserState userState)5800     boolean readMagnificationFollowTypingLocked(AccessibilityUserState userState) {
5801         final boolean followTypeEnabled = Settings.Secure.getIntForUser(
5802                 mContext.getContentResolver(),
5803                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED,
5804                 1, userState.mUserId) == 1;
5805         if (followTypeEnabled != userState.isMagnificationFollowTypingEnabled()) {
5806             userState.setMagnificationFollowTypingEnabled(followTypeEnabled);
5807             mMagnificationController.setMagnificationFollowTypingEnabled(followTypeEnabled);
5808             return true;
5809         }
5810         return false;
5811     }
5812 
5813     /**
5814      * Called when always on magnification feature flag flips to check if the feature should be
5815      * enabled for current user state.
5816      */
updateAlwaysOnMagnification()5817     public void updateAlwaysOnMagnification() {
5818         synchronized (mLock) {
5819             readAlwaysOnMagnificationLocked(getCurrentUserState());
5820         }
5821     }
5822 
5823     @GuardedBy("mLock")
readAlwaysOnMagnificationLocked(AccessibilityUserState userState)5824     boolean readAlwaysOnMagnificationLocked(AccessibilityUserState userState) {
5825         final boolean isSettingsAlwaysOnEnabled = Settings.Secure.getIntForUser(
5826                 mContext.getContentResolver(),
5827                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED,
5828                 1, userState.mUserId) == 1;
5829         final boolean isAlwaysOnFeatureFlagEnabled = mMagnificationController
5830                 .isAlwaysOnMagnificationFeatureFlagEnabled();
5831         final boolean isAlwaysOnEnabled = isAlwaysOnFeatureFlagEnabled && isSettingsAlwaysOnEnabled;
5832         if (isAlwaysOnEnabled != userState.isAlwaysOnMagnificationEnabled()) {
5833             userState.setAlwaysOnMagnificationEnabled(isAlwaysOnEnabled);
5834             mMagnificationController.setAlwaysOnMagnificationEnabled(isAlwaysOnEnabled);
5835             return true;
5836         }
5837         return false;
5838     }
5839 
5840     @Override
setGestureDetectionPassthroughRegion(int displayId, Region region)5841     public void setGestureDetectionPassthroughRegion(int displayId, Region region) {
5842         mMainHandler.sendMessage(
5843                 obtainMessage(
5844                         AccessibilityManagerService::setGestureDetectionPassthroughRegionInternal,
5845                         this,
5846                         displayId,
5847                         region));
5848     }
5849 
5850     @Override
setTouchExplorationPassthroughRegion(int displayId, Region region)5851     public void setTouchExplorationPassthroughRegion(int displayId, Region region) {
5852         mMainHandler.sendMessage(
5853                 obtainMessage(
5854                         AccessibilityManagerService::setTouchExplorationPassthroughRegionInternal,
5855                         this,
5856                         displayId,
5857                         region));
5858     }
5859 
setTouchExplorationPassthroughRegionInternal(int displayId, Region region)5860     private void setTouchExplorationPassthroughRegionInternal(int displayId, Region region) {
5861         synchronized (mLock) {
5862             if (mHasInputFilter && mInputFilter != null) {
5863                 mInputFilter.setTouchExplorationPassthroughRegion(displayId, region);
5864             }
5865         }
5866     }
5867 
setGestureDetectionPassthroughRegionInternal(int displayId, Region region)5868     private void setGestureDetectionPassthroughRegionInternal(int displayId, Region region) {
5869         synchronized (mLock) {
5870             if (mHasInputFilter && mInputFilter != null) {
5871                 mInputFilter.setGestureDetectionPassthroughRegion(displayId, region);
5872             }
5873         }
5874     }
5875 
5876     @Override
setServiceDetectsGesturesEnabled(int displayId, boolean mode)5877     public void setServiceDetectsGesturesEnabled(int displayId, boolean mode) {
5878         mMainHandler.sendMessage(
5879                 obtainMessage(AccessibilityManagerService::setServiceDetectsGesturesInternal, this,
5880                         displayId, mode));
5881     }
5882 
setServiceDetectsGesturesInternal(int displayId, boolean mode)5883     private void setServiceDetectsGesturesInternal(int displayId, boolean mode) {
5884         synchronized (mLock) {
5885             getCurrentUserStateLocked().setServiceDetectsGesturesEnabled(displayId, mode);
5886             if (mHasInputFilter && mInputFilter != null) {
5887                 mInputFilter.setServiceDetectsGesturesEnabled(displayId, mode);
5888             }
5889         }
5890     }
5891 
5892     @Override
requestTouchExploration(int displayId)5893     public void requestTouchExploration(int displayId) {
5894         mMainHandler.sendMessage(obtainMessage(
5895                 AccessibilityManagerService::requestTouchExplorationInternal, this, displayId));
5896     }
5897 
requestTouchExplorationInternal(int displayId)5898     private void requestTouchExplorationInternal(int displayId) {
5899         synchronized (mLock) {
5900             if (mHasInputFilter && mInputFilter != null) {
5901                 mInputFilter.requestTouchExploration(displayId);
5902             }
5903         }
5904     }
5905 
5906     @Override
requestDragging(int displayId, int pointerId)5907     public void requestDragging(int displayId, int pointerId) {
5908         mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::requestDraggingInternal,
5909                 this, displayId, pointerId));
5910     }
5911 
requestDraggingInternal(int displayId, int pointerId)5912     private void requestDraggingInternal(int displayId, int pointerId) {
5913         synchronized (mLock) {
5914             if (mHasInputFilter && mInputFilter != null) {
5915                 mInputFilter.requestDragging(displayId, pointerId);
5916             }
5917         }
5918     }
5919 
5920     @Override
requestDelegating(int displayId)5921     public void requestDelegating(int displayId) {
5922         mMainHandler.sendMessage(
5923                 obtainMessage(
5924                         AccessibilityManagerService::requestDelegatingInternal, this, displayId));
5925     }
5926 
requestDelegatingInternal(int displayId)5927     private void requestDelegatingInternal(int displayId) {
5928         synchronized (mLock) {
5929             if (mHasInputFilter && mInputFilter != null) {
5930                 mInputFilter.requestDelegating(displayId);
5931             }
5932         }
5933     }
5934 
5935     @Override
onDoubleTap(int displayId)5936     public void onDoubleTap(int displayId) {
5937         mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::onDoubleTapInternal,
5938                 this, displayId));
5939     }
5940 
onDoubleTapInternal(int displayId)5941     private void onDoubleTapInternal(int displayId) {
5942         AccessibilityInputFilter inputFilter = null;
5943         synchronized (mLock) {
5944             if (mHasInputFilter && mInputFilter != null) {
5945                 inputFilter = mInputFilter;
5946             }
5947         }
5948         if (inputFilter != null) {
5949             inputFilter.onDoubleTap(displayId);
5950         }
5951     }
5952 
5953     @Override
onDoubleTapAndHold(int displayId)5954     public void onDoubleTapAndHold(int displayId) {
5955         mMainHandler
5956                 .sendMessage(obtainMessage(AccessibilityManagerService::onDoubleTapAndHoldInternal,
5957                         this, displayId));
5958     }
5959 
5960     @Override
requestImeLocked(AbstractAccessibilityServiceConnection connection)5961     public void requestImeLocked(AbstractAccessibilityServiceConnection connection) {
5962         if (!(connection instanceof AccessibilityServiceConnection)
5963                 || (connection instanceof ProxyAccessibilityServiceConnection)) {
5964             if (DEBUG) {
5965                 Slog.d(LOG_TAG, "The connection should be a real connection but was "
5966                         + connection);
5967             }
5968             return;
5969         }
5970         AccessibilityServiceConnection realConnection = (AccessibilityServiceConnection) connection;
5971         mMainHandler.sendMessage(obtainMessage(
5972                 AccessibilityManagerService::createSessionForConnection, this, realConnection));
5973         mMainHandler.sendMessage(obtainMessage(
5974                 AccessibilityManagerService::bindAndStartInputForConnection, this, realConnection));
5975     }
5976 
5977     @Override
unbindImeLocked(AbstractAccessibilityServiceConnection connection)5978     public void unbindImeLocked(AbstractAccessibilityServiceConnection connection) {
5979         if (!(connection instanceof AccessibilityServiceConnection)
5980                 || (connection instanceof ProxyAccessibilityServiceConnection)) {
5981             if (DEBUG) {
5982                 Slog.d(LOG_TAG, "The connection should be a real connection but was "
5983                         + connection);
5984             }
5985             return;
5986         }
5987         AccessibilityServiceConnection realConnection = (AccessibilityServiceConnection) connection;
5988         mMainHandler.sendMessage(obtainMessage(
5989                 AccessibilityManagerService::unbindInputForConnection, this, realConnection));
5990     }
5991 
createSessionForConnection(AccessibilityServiceConnection connection)5992     private void createSessionForConnection(AccessibilityServiceConnection connection) {
5993         synchronized (mLock) {
5994             if (mInputSessionRequested) {
5995                 connection.createImeSessionLocked();
5996             }
5997         }
5998     }
5999 
bindAndStartInputForConnection(AccessibilityServiceConnection connection)6000     private void bindAndStartInputForConnection(AccessibilityServiceConnection connection) {
6001         synchronized (mLock) {
6002             if (mInputBound) {
6003                 connection.bindInputLocked();
6004                 connection.startInputLocked(mRemoteInputConnection, mEditorInfo, mRestarting);
6005             }
6006         }
6007     }
6008 
unbindInputForConnection(AccessibilityServiceConnection connection)6009     private void unbindInputForConnection(AccessibilityServiceConnection connection) {
6010         InputMethodManagerInternal.get()
6011                 .unbindAccessibilityFromCurrentClient(connection.mId, connection.mUserId);
6012         synchronized (mLock) {
6013             connection.unbindInputLocked();
6014         }
6015     }
6016 
onDoubleTapAndHoldInternal(int displayId)6017     private void onDoubleTapAndHoldInternal(int displayId) {
6018         synchronized (mLock) {
6019             if (mHasInputFilter && mInputFilter != null) {
6020                 mInputFilter.onDoubleTapAndHold(displayId);
6021             }
6022         }
6023     }
6024 
updateFocusAppearanceDataLocked(AccessibilityUserState userState)6025     private void updateFocusAppearanceDataLocked(AccessibilityUserState userState) {
6026         if (userState.mUserId != mCurrentUserId) {
6027             return;
6028         }
6029         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_SERVICE_CLIENT)) {
6030             mTraceManager.logTrace(LOG_TAG + ".updateFocusAppearanceDataLocked",
6031                     FLAGS_ACCESSIBILITY_SERVICE_CLIENT, "userState=" + userState);
6032         }
6033         mMainHandler.post(() -> {
6034             broadcastToClients(userState, ignoreRemoteException(client -> {
6035                 if (!mProxyManager.isProxyedDeviceId(client.mDeviceId)) {
6036                     client.mCallback.setFocusAppearance(userState.getFocusStrokeWidthLocked(),
6037                             userState.getFocusColorLocked());
6038                 }
6039             }));
6040         });
6041 
6042     }
6043 
getTraceManager()6044     public AccessibilityTraceManager getTraceManager() {
6045         return mTraceManager;
6046     }
6047 
6048     /**
6049      * Bind input for accessibility services which request ime capabilities.
6050      */
scheduleBindInput()6051     public void scheduleBindInput() {
6052         mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::bindInput, this));
6053     }
6054 
bindInput()6055     private void bindInput() {
6056         synchronized (mLock) {
6057             // Keep records of these in case new Accessibility Services are enabled.
6058             mInputBound = true;
6059             AccessibilityUserState userState = getCurrentUserStateLocked();
6060             for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
6061                 final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
6062                 if (service.requestImeApis()) {
6063                     service.bindInputLocked();
6064                 }
6065             }
6066         }
6067     }
6068 
6069     /**
6070      * Unbind input for accessibility services which request ime capabilities.
6071      */
scheduleUnbindInput()6072     public void scheduleUnbindInput() {
6073         mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::unbindInput, this));
6074     }
6075 
unbindInput()6076     private void unbindInput() {
6077         synchronized (mLock) {
6078             mInputBound = false;
6079             AccessibilityUserState userState = getCurrentUserStateLocked();
6080             for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
6081                 final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
6082                 if (service.requestImeApis()) {
6083                     service.unbindInputLocked();
6084                 }
6085             }
6086         }
6087     }
6088 
6089     /**
6090      * Start input for accessibility services which request ime capabilities.
6091      */
scheduleStartInput(IRemoteAccessibilityInputConnection connection, EditorInfo editorInfo, boolean restarting)6092     public void scheduleStartInput(IRemoteAccessibilityInputConnection connection,
6093             EditorInfo editorInfo, boolean restarting) {
6094         mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::startInput, this,
6095                 connection, editorInfo, restarting));
6096     }
6097 
startInput(IRemoteAccessibilityInputConnection connection, EditorInfo editorInfo, boolean restarting)6098     private void startInput(IRemoteAccessibilityInputConnection connection, EditorInfo editorInfo,
6099             boolean restarting) {
6100         synchronized (mLock) {
6101             // Keep records of these in case new Accessibility Services are enabled.
6102             mRemoteInputConnection = connection;
6103             mEditorInfo = editorInfo;
6104             mRestarting = restarting;
6105             AccessibilityUserState userState = getCurrentUserStateLocked();
6106             for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
6107                 final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
6108                 if (service.requestImeApis()) {
6109                     service.startInputLocked(connection, editorInfo, restarting);
6110                 }
6111             }
6112         }
6113     }
6114 
6115     /**
6116      * Request input sessions from all accessibility services which request ime capabilities and
6117      * whose id is not in the ignoreSet
6118      */
scheduleCreateImeSession(ArraySet<Integer> ignoreSet)6119     public void scheduleCreateImeSession(ArraySet<Integer> ignoreSet) {
6120         mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::createImeSession,
6121                 this, ignoreSet));
6122     }
6123 
createImeSession(ArraySet<Integer> ignoreSet)6124     private void createImeSession(ArraySet<Integer> ignoreSet) {
6125         synchronized (mLock) {
6126             mInputSessionRequested = true;
6127             AccessibilityUserState userState = getCurrentUserStateLocked();
6128             for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
6129                 final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
6130                 if ((!ignoreSet.contains(service.mId)) && service.requestImeApis()) {
6131                     service.createImeSessionLocked();
6132                 }
6133             }
6134         }
6135     }
6136 
6137     /**
6138      * Enable or disable the sessions.
6139      *
6140      * @param sessions Sessions to enable or disable.
6141      * @param enabled True if enable the sessions or false if disable the sessions.
6142      */
scheduleSetImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions, boolean enabled)6143     public void scheduleSetImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions,
6144             boolean enabled) {
6145         mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::setImeSessionEnabled,
6146                 this, sessions, enabled));
6147     }
6148 
setImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions, boolean enabled)6149     private void setImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions,
6150             boolean enabled) {
6151         synchronized (mLock) {
6152             AccessibilityUserState userState = getCurrentUserStateLocked();
6153             for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
6154                 final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
6155                 if (sessions.contains(service.mId) && service.requestImeApis()) {
6156                     service.setImeSessionEnabledLocked(sessions.get(service.mId), enabled);
6157                 }
6158             }
6159         }
6160     }
6161 
6162     @Override
6163     @EnforcePermission(INJECT_EVENTS)
injectInputEventToInputFilter(InputEvent event)6164     public void injectInputEventToInputFilter(InputEvent event) {
6165         injectInputEventToInputFilter_enforcePermission();
6166         synchronized (mLock) {
6167             final long endMillis =
6168                     SystemClock.uptimeMillis() + WAIT_INPUT_FILTER_INSTALL_TIMEOUT_MS;
6169             while (!mInputFilterInstalled && (SystemClock.uptimeMillis() < endMillis)) {
6170                 try {
6171                     mLock.wait(endMillis - SystemClock.uptimeMillis());
6172                 } catch (InterruptedException ie) {
6173                     /* ignore */
6174                 }
6175             }
6176         }
6177 
6178         if (mInputFilterInstalled && mInputFilter != null) {
6179             mInputFilter.onInputEvent(event,
6180                     WindowManagerPolicy.FLAG_PASS_TO_USER | WindowManagerPolicy.FLAG_INJECTED);
6181         } else {
6182             Slog.w(LOG_TAG, "Cannot injectInputEventToInputFilter because the "
6183                     + "AccessibilityInputFilter is not installed.");
6184         }
6185     }
6186 
6187     private final class SendWindowStateChangedEventRunnable implements Runnable {
6188 
6189         private final AccessibilityEvent mPendingEvent;
6190         private final int mWindowId;
6191 
SendWindowStateChangedEventRunnable(@onNull AccessibilityEvent event)6192         SendWindowStateChangedEventRunnable(@NonNull AccessibilityEvent event) {
6193             mPendingEvent = event;
6194             mWindowId = event.getWindowId();
6195         }
6196 
6197         @Override
run()6198         public void run() {
6199             synchronized (mLock) {
6200                 Slog.w(LOG_TAG, " wait for adding window timeout: " + mWindowId);
6201                 sendPendingEventLocked();
6202             }
6203         }
6204 
sendPendingEventLocked()6205         private void sendPendingEventLocked() {
6206             mSendWindowStateChangedEventRunnables.remove(this);
6207             dispatchAccessibilityEventLocked(mPendingEvent);
6208         }
6209 
getWindowId()6210         private int getWindowId() {
6211             return mWindowId;
6212         }
6213     }
6214 
6215     @VisibleForTesting
6216     public static class ManagerPackageMonitor extends PackageMonitor {
6217         private final AccessibilityManagerService mManagerService;
ManagerPackageMonitor(AccessibilityManagerService managerService)6218         public ManagerPackageMonitor(AccessibilityManagerService managerService) {
6219             super(/* supportsPackageRestartQuery = */ true);
6220             mManagerService = managerService;
6221         }
6222 
6223         @Override
onSomePackagesChanged()6224         public void onSomePackagesChanged() {
6225             if (mManagerService.mTraceManager.isA11yTracingEnabledForTypes(
6226                     FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
6227                 mManagerService.mTraceManager.logTrace(LOG_TAG + ".PM.onSomePackagesChanged",
6228                         FLAGS_PACKAGE_BROADCAST_RECEIVER);
6229             }
6230 
6231             final int userId = getChangingUserId();
6232             List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos = mManagerService
6233                     .parseAccessibilityServiceInfos(userId);
6234             List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos = mManagerService
6235                     .parseAccessibilityShortcutInfos(userId);
6236             synchronized (mManagerService.getLock()) {
6237                 // Only the profile parent can install accessibility services.
6238                 // Therefore we ignore packages from linked profiles.
6239                 if (userId != mManagerService.getCurrentUserIdLocked()) {
6240                     return;
6241                 }
6242 
6243                 // Only continue setting up the packages if the service has been initialized.
6244                 // See: b/340927041
6245                 if (Flags.skipPackageChangeBeforeUserSwitch()
6246                         && !mManagerService.isServiceInitializedLocked()) {
6247                     Slog.w(LOG_TAG,
6248                             "onSomePackagesChanged: service not initialized, skip the callback.");
6249                     return;
6250                 }
6251                 mManagerService.onSomePackagesChangedLocked(parsedAccessibilityServiceInfos,
6252                         parsedAccessibilityShortcutInfos);
6253             }
6254         }
6255 
6256         @Override
onPackageUpdateFinished(String packageName, int uid)6257         public void onPackageUpdateFinished(String packageName, int uid) {
6258             // The package should already be removed from mBoundServices, and added into
6259             // mBindingServices in binderDied() during updating. Remove services from  this
6260             // package from mBindingServices, and then update the user state to re-bind new
6261             // versions of them.
6262             if (mManagerService.mTraceManager.isA11yTracingEnabledForTypes(
6263                     FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
6264                 mManagerService.mTraceManager.logTrace(
6265                         LOG_TAG + ".PM.onPackageUpdateFinished",
6266                         FLAGS_PACKAGE_BROADCAST_RECEIVER,
6267                         "packageName=" + packageName + ";uid=" + uid);
6268             }
6269             final int userId = getChangingUserId();
6270             List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos = mManagerService
6271                     .parseAccessibilityServiceInfos(userId);
6272             List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos =
6273                     mManagerService.parseAccessibilityShortcutInfos(userId);
6274             synchronized (mManagerService.getLock()) {
6275                 if (userId != mManagerService.getCurrentUserIdLocked()) {
6276                     return;
6277                 }
6278                 final AccessibilityUserState userState = mManagerService.getUserStateLocked(userId);
6279                 final boolean reboundAService = userState.getBindingServicesLocked().removeIf(
6280                         component -> component != null
6281                                 && component.getPackageName().equals(packageName))
6282                         || userState.mCrashedServices.removeIf(component -> component != null
6283                         && component.getPackageName().equals(packageName));
6284                 // Reloads the installed services info to make sure the rebound service could
6285                 // get a new one.
6286                 userState.mInstalledServices.clear();
6287                 final boolean configurationChanged;
6288                 configurationChanged = mManagerService.readConfigurationForUserStateLocked(
6289                         userState, parsedAccessibilityServiceInfos,
6290                         parsedAccessibilityShortcutInfos);
6291                 if (reboundAService || configurationChanged) {
6292                     mManagerService.onUserStateChangedLocked(userState);
6293                 }
6294                 // Passing 0 for restoreFromSdkInt to have this migration check execute each
6295                 // time. It can make sure a11y button settings are correctly if there's an a11y
6296                 // service updated and modifies the a11y button configuration.
6297                 mManagerService.migrateAccessibilityButtonSettingsIfNecessaryLocked(
6298                         userState, packageName, /* restoreFromSdkInt = */0);
6299             }
6300         }
6301 
6302         @Override
onPackageRemoved(String packageName, int uid)6303         public void onPackageRemoved(String packageName, int uid) {
6304             if (mManagerService.mTraceManager.isA11yTracingEnabledForTypes(
6305                     FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
6306                 mManagerService.mTraceManager.logTrace(LOG_TAG + ".PM.onPackageRemoved",
6307                         FLAGS_PACKAGE_BROADCAST_RECEIVER,
6308                         "packageName=" + packageName + ";uid=" + uid);
6309             }
6310 
6311             synchronized (mManagerService.getLock()) {
6312                 final int userId = getChangingUserId();
6313                 // Only the profile parent can install accessibility services.
6314                 // Therefore we ignore packages from linked profiles.
6315                 if (userId != mManagerService.getCurrentUserIdLocked()) {
6316                     return;
6317                 }
6318                 mManagerService.onPackageRemovedLocked(packageName);
6319             }
6320         }
6321 
6322         /**
6323          * Handles instances in which a package or packages have forcibly stopped.
6324          *
6325          * @param intent intent containing package event information.
6326          * @param uid linux process user id (different from Android user id).
6327          * @param packages array of package names that have stopped.
6328          * @param doit whether to try and handle the stop or just log the trace.
6329          *
6330          * @return {@code true} if doit == {@code false}
6331          * and at least one of the provided packages is enabled.
6332          * In any other case, returns {@code false}.
6333          * This is to indicate whether further action is necessary.
6334          */
6335         @Override
onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit)6336         public boolean onHandleForceStop(Intent intent, String[] packages,
6337                 int uid, boolean doit) {
6338             if (mManagerService.mTraceManager.isA11yTracingEnabledForTypes(
6339                     FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
6340                 mManagerService.mTraceManager.logTrace(LOG_TAG + ".PM.onHandleForceStop",
6341                         FLAGS_PACKAGE_BROADCAST_RECEIVER,
6342                         "intent=" + intent + ";packages=" + Arrays.toString(packages)
6343                                 + ";uid=" + uid + ";doit=" + doit);
6344             }
6345             synchronized (mManagerService.getLock()) {
6346                 final int userId = getChangingUserId();
6347                 // Only the profile parent can install accessibility services.
6348                 // Therefore we ignore packages from linked profiles.
6349                 if (userId != mManagerService.getCurrentUserIdLocked()) {
6350                     return false;
6351                 }
6352                 final AccessibilityUserState userState = mManagerService.getUserStateLocked(userId);
6353 
6354                 if (Flags.managerPackageMonitorLogicFix()) {
6355                     if (!doit) {
6356                         // if we're not handling the stop here, then we only need to know
6357                         // if any of the force-stopped packages are currently enabled.
6358                         return userState.mEnabledServices.stream().anyMatch(
6359                                 (comp) -> Arrays.stream(packages).anyMatch(
6360                                         (pkg) -> pkg.equals(comp.getPackageName()))
6361                         );
6362                     } else if (mManagerService.onPackagesForceStoppedLocked(packages, userState)) {
6363                         mManagerService.onUserStateChangedLocked(userState);
6364                     }
6365                     return false;
6366                 } else {
6367                     // this old logic did not properly indicate when base packageMonitor's routine
6368                     // should handle stopping the package.
6369                     if (doit && mManagerService.onPackagesForceStoppedLocked(packages, userState)) {
6370                         mManagerService.onUserStateChangedLocked(userState);
6371                         return false;
6372                     } else {
6373                         return true;
6374                     }
6375                 }
6376             }
6377         }
6378 
6379         @Override
onPackageChanged(String packageName, int uid, String[] components)6380         public boolean onPackageChanged(String packageName, int uid, String[] components) {
6381             // We care about all package changes, not just the whole package itself which is
6382             // default behavior.
6383             return true;
6384         }
6385     }
6386 
sendPendingWindowStateChangedEventsForAvailableWindowLocked(int windowId)6387     void sendPendingWindowStateChangedEventsForAvailableWindowLocked(int windowId) {
6388         final int eventSize =  mSendWindowStateChangedEventRunnables.size();
6389         for (int i = eventSize - 1; i >= 0; i--) {
6390             final SendWindowStateChangedEventRunnable runnable =
6391                     mSendWindowStateChangedEventRunnables.get(i);
6392             if (runnable.getWindowId() == windowId) {
6393                 mMainHandler.removeCallbacks(runnable);
6394                 runnable.sendPendingEventLocked();
6395             }
6396         }
6397     }
6398 
6399     /**
6400      * Postpones the {@link AccessibilityEvent} with
6401      * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}
6402      * which doesn't have the corresponding window until the window is added or timeout.
6403      *
6404      * @return {@code true} if the event is postponed.
6405      */
postponeWindowStateEvent(AccessibilityEvent event)6406     private boolean postponeWindowStateEvent(AccessibilityEvent event) {
6407         synchronized (mLock) {
6408             final int resolvedWindowId = mA11yWindowManager.resolveParentWindowIdLocked(
6409                     event.getWindowId());
6410             if (mA11yWindowManager.findWindowInfoByIdLocked(resolvedWindowId) != null) {
6411                 return false;
6412             }
6413             final SendWindowStateChangedEventRunnable pendingRunnable =
6414                     new SendWindowStateChangedEventRunnable(new AccessibilityEvent(event));
6415             mMainHandler.postDelayed(pendingRunnable,
6416                     POSTPONE_WINDOW_STATE_CHANGED_EVENT_TIMEOUT_MILLIS);
6417             mSendWindowStateChangedEventRunnables.add(pendingRunnable);
6418             return true;
6419         }
6420     }
6421 
6422     /** Used to attach accessibility overlays from the system itself i.e. magnification. */
6423     @EnforcePermission(INTERNAL_SYSTEM_WINDOW)
6424     @Override
attachAccessibilityOverlayToDisplay(int displayId, SurfaceControl sc)6425     public void attachAccessibilityOverlayToDisplay(int displayId, SurfaceControl sc) {
6426         attachAccessibilityOverlayToDisplay_enforcePermission();
6427         mMainHandler.sendMessage(
6428                 obtainMessage(
6429                         AccessibilityManagerService::attachAccessibilityOverlayToDisplayInternal,
6430                         this,
6431                         -1,
6432                         displayId,
6433                         sc,
6434                         null));
6435     }
6436 
6437     /** Called by services to attach accessibility overlays. */
6438     @Override
attachAccessibilityOverlayToDisplay( int interactionId, int displayId, SurfaceControl sc, IAccessibilityInteractionConnectionCallback callback)6439     public void attachAccessibilityOverlayToDisplay(
6440             int interactionId,
6441             int displayId,
6442             SurfaceControl sc,
6443             IAccessibilityInteractionConnectionCallback callback) {
6444         mMainHandler.sendMessage(
6445                 obtainMessage(
6446                         AccessibilityManagerService::attachAccessibilityOverlayToDisplayInternal,
6447                         this,
6448                         interactionId,
6449                         displayId,
6450                         sc,
6451                         callback));
6452     }
6453 
attachAccessibilityOverlayToDisplayInternal( int interactionId, int displayId, SurfaceControl sc, IAccessibilityInteractionConnectionCallback callback)6454     void attachAccessibilityOverlayToDisplayInternal(
6455             int interactionId,
6456             int displayId,
6457             SurfaceControl sc,
6458             IAccessibilityInteractionConnectionCallback callback) {
6459         int result;
6460         if (!mA11yOverlayLayers.contains(displayId)) {
6461             mA11yOverlayLayers.put(displayId, mWindowManagerService.getA11yOverlayLayer(displayId));
6462         }
6463         SurfaceControl parent = mA11yOverlayLayers.get(displayId);
6464         if (parent == null) {
6465             Slog.e(LOG_TAG, "Unable to get accessibility overlay SurfaceControl.");
6466             mA11yOverlayLayers.remove(displayId);
6467             result = AccessibilityService.OVERLAY_RESULT_INVALID;
6468         } else {
6469             SurfaceControl.Transaction t = new SurfaceControl.Transaction();
6470             t.reparent(sc, parent).setTrustedOverlay(sc, true).apply();
6471             t.close();
6472             result = AccessibilityService.OVERLAY_RESULT_SUCCESS;
6473         }
6474 
6475         if (callback != null) {
6476             // Send the result back to the service.
6477             try {
6478                 callback.sendAttachOverlayResult(result, interactionId);
6479             } catch (RemoteException re) {
6480                 Slog.e(LOG_TAG, "Exception while attaching overlay.", re);
6481                 // the other side will time out
6482             }
6483         }
6484     }
6485 
6486     /**
6487      * Bypasses the timeout restriction if volume key shortcut assigned.
6488      */
skipVolumeShortcutDialogTimeoutRestriction(int userId)6489     private void skipVolumeShortcutDialogTimeoutRestriction(int userId) {
6490         persistIntToSetting(
6491                 userId,
6492                 Settings.Secure.SKIP_ACCESSIBILITY_SHORTCUT_DIALOG_TIMEOUT_RESTRICTION,
6493                 /* true */ 1);
6494     }
6495 
6496     /**
6497      * Log the metric when the user add/remove qs shortcut for accessibility features. Use the
6498      * callingUid to know where the users configure the a11y qs shortcuts.
6499      */
logMetricForQsShortcutConfiguration(boolean enable, int numOfFeatures)6500     private void logMetricForQsShortcutConfiguration(boolean enable, int numOfFeatures) {
6501         if (numOfFeatures <= 0) {
6502             // Skip logging metric if no a11y features are configured
6503             return;
6504         }
6505         String metricId = enable ? METRIC_ID_QS_SHORTCUT_ADD : METRIC_ID_QS_SHORTCUT_REMOVE;
6506         Counter.logIncrementWithUid(metricId, Binder.getCallingUid(), numOfFeatures);
6507     }
6508 }
6509