1 /*
2  * Copyright (C) 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 android.view.accessibility;
18 
19 import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_ENABLE_ACCESSIBILITY_VOLUME;
20 import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
21 
22 import android.Manifest;
23 import android.accessibilityservice.AccessibilityService;
24 import android.accessibilityservice.AccessibilityServiceInfo;
25 import android.accessibilityservice.AccessibilityServiceInfo.FeedbackType;
26 import android.accessibilityservice.AccessibilityShortcutInfo;
27 import android.annotation.CallbackExecutor;
28 import android.annotation.ColorInt;
29 import android.annotation.FlaggedApi;
30 import android.annotation.IntDef;
31 import android.annotation.NonNull;
32 import android.annotation.Nullable;
33 import android.annotation.RequiresPermission;
34 import android.annotation.SdkConstant;
35 import android.annotation.SystemApi;
36 import android.annotation.SystemService;
37 import android.annotation.TestApi;
38 import android.annotation.UserIdInt;
39 import android.app.RemoteAction;
40 import android.compat.annotation.UnsupportedAppUsage;
41 import android.content.ComponentName;
42 import android.content.Context;
43 import android.content.Intent;
44 import android.content.pm.ActivityInfo;
45 import android.content.pm.PackageManager;
46 import android.content.pm.ResolveInfo;
47 import android.content.pm.ServiceInfo;
48 import android.content.res.Resources;
49 import android.os.Binder;
50 import android.os.Build;
51 import android.os.Bundle;
52 import android.os.Handler;
53 import android.os.HandlerExecutor;
54 import android.os.IBinder;
55 import android.os.Looper;
56 import android.os.Message;
57 import android.os.Process;
58 import android.os.RemoteException;
59 import android.os.ServiceManager;
60 import android.os.SystemClock;
61 import android.os.UserHandle;
62 import android.util.ArrayMap;
63 import android.util.Log;
64 import android.util.SparseArray;
65 import android.view.IWindow;
66 import android.view.SurfaceControl;
67 import android.view.View;
68 import android.view.accessibility.AccessibilityEvent.EventType;
69 
70 import com.android.internal.R;
71 import com.android.internal.accessibility.common.ShortcutConstants;
72 import com.android.internal.annotations.VisibleForTesting;
73 import com.android.internal.util.IntPair;
74 
75 import org.xmlpull.v1.XmlPullParserException;
76 
77 import java.io.IOException;
78 import java.lang.annotation.Retention;
79 import java.lang.annotation.RetentionPolicy;
80 import java.util.ArrayList;
81 import java.util.Collections;
82 import java.util.List;
83 import java.util.Map;
84 import java.util.Set;
85 import java.util.concurrent.Executor;
86 
87 /**
88  * System level service that serves as an event dispatch for {@link AccessibilityEvent}s,
89  * and provides facilities for querying the accessibility state of the system.
90  * Accessibility events are generated when something notable happens in the user interface,
91  * for example an {@link android.app.Activity} starts, the focus or selection of a
92  * {@link android.view.View} changes etc. Parties interested in handling accessibility
93  * events implement and register an accessibility service which extends
94  * {@link android.accessibilityservice.AccessibilityService}.
95  *
96  * @see AccessibilityEvent
97  * @see AccessibilityNodeInfo
98  * @see android.accessibilityservice.AccessibilityService
99  * @see Context#getSystemService
100  * @see Context#ACCESSIBILITY_SERVICE
101  */
102 @SystemService(Context.ACCESSIBILITY_SERVICE)
103 public final class AccessibilityManager {
104     private static final boolean DEBUG = false;
105 
106     private static final String LOG_TAG = "AccessibilityManager";
107 
108     /** @hide */
109     public static final int STATE_FLAG_ACCESSIBILITY_ENABLED = 1 /* << 0 */;
110 
111     /** @hide */
112     public static final int STATE_FLAG_TOUCH_EXPLORATION_ENABLED = 1 << 1;
113 
114     /** @hide */
115     public static final int STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED = 1 << 2;
116 
117     /** @hide */
118     public static final int STATE_FLAG_DISPATCH_DOUBLE_TAP = 1 << 3;
119 
120     /** @hide */
121     public static final int STATE_FLAG_REQUEST_MULTI_FINGER_GESTURES = 1 << 4;
122 
123     /** @hide */
124     public static final int STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_ENABLED = 1 << 8;
125     /** @hide */
126     public static final int STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_CB_ENABLED = 1 << 9;
127     /** @hide */
128     public static final int STATE_FLAG_TRACE_A11Y_INTERACTION_CLIENT_ENABLED = 1 << 10;
129     /** @hide */
130     public static final int STATE_FLAG_TRACE_A11Y_SERVICE_ENABLED = 1 << 11;
131     /** @hide */
132     public static final int STATE_FLAG_AUDIO_DESCRIPTION_BY_DEFAULT_ENABLED = 1 << 12;
133 
134     /** @hide */
135     public static final int DALTONIZER_DISABLED = -1;
136 
137     /** @hide */
138     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
139     public static final int DALTONIZER_SIMULATE_MONOCHROMACY = 0;
140 
141     /** @hide */
142     public static final int DALTONIZER_CORRECT_DEUTERANOMALY = 12;
143 
144     /** @hide */
145     public static final int AUTOCLICK_DELAY_DEFAULT = 600;
146 
147     /**
148      * Activity action: Launch UI to manage which accessibility service or feature is assigned
149      * to the navigation bar Accessibility button.
150      * <p>
151      * Input: Nothing.
152      * </p>
153      * <p>
154      * Output: Nothing.
155      * </p>
156      *
157      * @hide
158      */
159     @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
160     public static final String ACTION_CHOOSE_ACCESSIBILITY_BUTTON =
161             "com.android.internal.intent.action.CHOOSE_ACCESSIBILITY_BUTTON";
162 
163     /** @hide */
164     public static final int FLASH_REASON_CALL = 1;
165 
166     /** @hide */
167     public static final int FLASH_REASON_ALARM = 2;
168 
169     /** @hide */
170     public static final int FLASH_REASON_NOTIFICATION = 3;
171 
172     /** @hide */
173     public static final int FLASH_REASON_PREVIEW = 4;
174 
175     /**
176      * Annotations for content flag of UI.
177      * @hide
178      */
179     @Retention(RetentionPolicy.SOURCE)
180     @IntDef(flag = true, prefix = { "FLAG_CONTENT_" }, value = {
181             FLAG_CONTENT_ICONS,
182             FLAG_CONTENT_TEXT,
183             FLAG_CONTENT_CONTROLS
184     })
185     public @interface ContentFlag {}
186 
187     /**
188      * Annotations for reason of Flash notification.
189      * @hide
190      */
191     @Retention(RetentionPolicy.SOURCE)
192     @IntDef(prefix = { "FLASH_REASON_" }, value = {
193             FLASH_REASON_CALL,
194             FLASH_REASON_ALARM,
195             FLASH_REASON_NOTIFICATION,
196             FLASH_REASON_PREVIEW
197     })
198     public @interface FlashNotificationReason {}
199 
200     /**
201      * Use this flag to indicate the content of a UI that times out contains icons.
202      *
203      * @see #getRecommendedTimeoutMillis(int, int)
204      */
205     public static final int FLAG_CONTENT_ICONS = 1;
206 
207     /**
208      * Use this flag to indicate the content of a UI that times out contains text.
209      *
210      * @see #getRecommendedTimeoutMillis(int, int)
211      */
212     public static final int FLAG_CONTENT_TEXT = 2;
213 
214     /**
215      * Use this flag to indicate the content of a UI that times out contains interactive controls.
216      *
217      * @see #getRecommendedTimeoutMillis(int, int)
218      */
219     public static final int FLAG_CONTENT_CONTROLS = 4;
220 
221     @UnsupportedAppUsage
222     static final Object sInstanceSync = new Object();
223 
224     @UnsupportedAppUsage
225     private static AccessibilityManager sInstance;
226 
227     @UnsupportedAppUsage
228     private final Object mLock = new Object();
229 
230     @UnsupportedAppUsage
231     private IAccessibilityManager mService;
232 
233     @UnsupportedAppUsage
234     final int mUserId;
235 
236     @UnsupportedAppUsage
237     final Handler mHandler;
238 
239     final Handler.Callback mCallback;
240 
241     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
242     boolean mIsEnabled;
243 
244     int mRelevantEventTypes = AccessibilityEvent.TYPES_ALL_MASK;
245 
246     int mInteractiveUiTimeout;
247     int mNonInteractiveUiTimeout;
248 
249     boolean mIsTouchExplorationEnabled;
250 
251     @UnsupportedAppUsage(trackingBug = 123768939L)
252     boolean mIsHighTextContrastEnabled;
253 
254     boolean mIsAudioDescriptionByDefaultRequested;
255 
256     // accessibility tracing state
257     int mAccessibilityTracingState = 0;
258 
259     AccessibilityPolicy mAccessibilityPolicy;
260 
261     private int mPerformingAction = 0;
262 
263     /** The stroke width of the focus rectangle in pixels */
264     private int mFocusStrokeWidth;
265     /** The color of the focus rectangle */
266     private int mFocusColor;
267 
268     @UnsupportedAppUsage
269     private final ArrayMap<AccessibilityStateChangeListener, Handler>
270             mAccessibilityStateChangeListeners = new ArrayMap<>();
271 
272     private final ArrayMap<TouchExplorationStateChangeListener, Handler>
273             mTouchExplorationStateChangeListeners = new ArrayMap<>();
274 
275     private final ArrayMap<HighTextContrastChangeListener, Handler>
276             mHighTextContrastStateChangeListeners = new ArrayMap<>();
277 
278     private final ArrayMap<AccessibilityServicesStateChangeListener, Executor>
279             mServicesStateChangeListeners = new ArrayMap<>();
280 
281     private final ArrayMap<AudioDescriptionRequestedChangeListener, Executor>
282             mAudioDescriptionRequestedChangeListeners = new ArrayMap<>();
283 
284     private boolean mRequestFromAccessibilityTool;
285 
286     /**
287      * Map from a view's accessibility id to the list of request preparers set for that view
288      */
289     private SparseArray<List<AccessibilityRequestPreparer>> mRequestPreparerLists;
290 
291     /**
292      * Binder for flash notification.
293      *
294      * @see #startFlashNotificationSequence(Context, int)
295      */
296     private final Binder mBinder = new Binder();
297 
298     /**
299      * Listener for the system accessibility state. To listen for changes to the
300      * accessibility state on the device, implement this interface and register
301      * it with the system by calling {@link #addAccessibilityStateChangeListener}.
302      */
303     public interface AccessibilityStateChangeListener {
304 
305         /**
306          * Called when the accessibility enabled state changes.
307          *
308          * @param enabled Whether accessibility is enabled.
309          */
onAccessibilityStateChanged(boolean enabled)310         void onAccessibilityStateChanged(boolean enabled);
311     }
312 
313     /**
314      * Listener for the system touch exploration state. To listen for changes to
315      * the touch exploration state on the device, implement this interface and
316      * register it with the system by calling
317      * {@link #addTouchExplorationStateChangeListener}.
318      */
319     public interface TouchExplorationStateChangeListener {
320 
321         /**
322          * Called when the touch exploration enabled state changes.
323          *
324          * @param enabled Whether touch exploration is enabled.
325          */
onTouchExplorationStateChanged(boolean enabled)326         void onTouchExplorationStateChanged(boolean enabled);
327     }
328 
329     /**
330      * Listener for changes to the state of accessibility services.
331      *
332      * <p>
333      * This refers to changes to {@link AccessibilityServiceInfo}, including:
334      * <ul>
335      *     <li>Whenever a service is enabled or disabled, or its info has been set or removed.</li>
336      *     <li>Whenever a metadata attribute of any running service's info changes.</li>
337      * </ul>
338      *
339      * @see #getEnabledAccessibilityServiceList for a list of infos of the enabled accessibility
340      * services.
341      * @see #addAccessibilityServicesStateChangeListener
342      *
343      */
344     public interface AccessibilityServicesStateChangeListener {
345 
346         /**
347          * Called when the state of accessibility services changes.
348          *
349          * @param manager The manager that is calling back
350          */
onAccessibilityServicesStateChanged(@onNull AccessibilityManager manager)351         void onAccessibilityServicesStateChanged(@NonNull  AccessibilityManager manager);
352     }
353 
354     /**
355      * Listener for the system high text contrast state. To listen for changes to
356      * the high text contrast state on the device, implement this interface and
357      * register it with the system by calling
358      * {@link #addHighTextContrastStateChangeListener}.
359      *
360      * @hide
361      */
362     public interface HighTextContrastChangeListener {
363 
364         /**
365          * Called when the high text contrast enabled state changes.
366          *
367          * @param enabled Whether high text contrast is enabled.
368          */
onHighTextContrastStateChanged(boolean enabled)369         void onHighTextContrastStateChanged(boolean enabled);
370     }
371 
372     /**
373      * Listener for the audio description by default state. To listen for
374      * changes to the audio description by default state on the device,
375      * implement this interface and register it with the system by calling
376      * {@link #addAudioDescriptionRequestedChangeListener}.
377      */
378     public interface AudioDescriptionRequestedChangeListener {
379         /**
380          * Called when the audio description enabled state changes.
381          *
382          * @param enabled Whether audio description by default is enabled.
383          */
onAudioDescriptionRequestedChanged(boolean enabled)384         void onAudioDescriptionRequestedChanged(boolean enabled);
385     }
386 
387     /**
388      * Policy to inject behavior into the accessibility manager.
389      *
390      * @hide
391      */
392     public interface AccessibilityPolicy {
393         /**
394          * Checks whether accessibility is enabled.
395          *
396          * @param accessibilityEnabled Whether the accessibility layer is enabled.
397          * @return whether accessibility is enabled.
398          */
isEnabled(boolean accessibilityEnabled)399         boolean isEnabled(boolean accessibilityEnabled);
400 
401         /**
402          * Notifies the policy for an accessibility event.
403          *
404          * @param event The event.
405          * @param accessibilityEnabled Whether the accessibility layer is enabled.
406          * @param relevantEventTypes The events relevant events.
407          * @return The event to dispatch or null.
408          */
onAccessibilityEvent(@onNull AccessibilityEvent event, boolean accessibilityEnabled, @EventType int relevantEventTypes)409         @Nullable AccessibilityEvent onAccessibilityEvent(@NonNull AccessibilityEvent event,
410                 boolean accessibilityEnabled, @EventType int relevantEventTypes);
411 
412         /**
413          * Gets the list of relevant events.
414          *
415          * @param relevantEventTypes The relevant events.
416          * @return The relevant events to report.
417          */
getRelevantEventTypes(@ventType int relevantEventTypes)418         @EventType int getRelevantEventTypes(@EventType int relevantEventTypes);
419 
420         /**
421          * Gets the list of installed services to report.
422          *
423          * @param installedService The installed services.
424          * @return The services to report.
425          */
getInstalledAccessibilityServiceList( @ullable List<AccessibilityServiceInfo> installedService)426         @NonNull List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(
427                 @Nullable List<AccessibilityServiceInfo> installedService);
428 
429         /**
430          * Gets the list of enabled accessibility services.
431          *
432          * @param feedbackTypeFlags The feedback type to query for.
433          * @param enabledService The enabled services.
434          * @return The services to report.
435          */
getEnabledAccessibilityServiceList( @eedbackType int feedbackTypeFlags, @Nullable List<AccessibilityServiceInfo> enabledService)436         @Nullable List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(
437                 @FeedbackType int feedbackTypeFlags,
438                 @Nullable List<AccessibilityServiceInfo> enabledService);
439     }
440 
441     private final IAccessibilityManagerClient.Stub mClient =
442             new IAccessibilityManagerClient.Stub() {
443         @Override
444         public void setState(int state) {
445             // We do not want to change this immediately as the application may
446             // have already checked that accessibility is on and fired an event,
447             // that is now propagating up the view tree, Hence, if accessibility
448             // is now off an exception will be thrown. We want to have the exception
449             // enforcement to guard against apps that fire unnecessary accessibility
450             // events when accessibility is off.
451             mHandler.obtainMessage(MyCallback.MSG_SET_STATE, state, 0).sendToTarget();
452         }
453 
454         @Override
455         public void notifyServicesStateChanged(long updatedUiTimeout) {
456             updateUiTimeout(updatedUiTimeout);
457 
458             final ArrayMap<AccessibilityServicesStateChangeListener, Executor> listeners;
459             synchronized (mLock) {
460                 if (mServicesStateChangeListeners.isEmpty()) {
461                     return;
462                 }
463                 listeners = new ArrayMap<>(mServicesStateChangeListeners);
464             }
465 
466             int numListeners = listeners.size();
467             for (int i = 0; i < numListeners; i++) {
468                 final AccessibilityServicesStateChangeListener listener =
469                         mServicesStateChangeListeners.keyAt(i);
470                 mServicesStateChangeListeners.valueAt(i).execute(() -> listener
471                         .onAccessibilityServicesStateChanged(AccessibilityManager.this));
472             }
473         }
474 
475         @Override
476         public void setRelevantEventTypes(int eventTypes) {
477             mRelevantEventTypes = eventTypes;
478         }
479 
480         @Override
481         public void setFocusAppearance(int strokeWidth, int color) {
482             synchronized (mLock) {
483                 updateFocusAppearanceLocked(strokeWidth, color);
484             }
485         }
486     };
487 
488     /**
489      * Get an AccessibilityManager instance (create one if necessary).
490      *
491      * @param context Context in which this manager operates.
492      *
493      * @hide
494      */
495     @UnsupportedAppUsage
getInstance(Context context)496     public static AccessibilityManager getInstance(Context context) {
497         synchronized (sInstanceSync) {
498             if (sInstance == null) {
499                 final int userId;
500                 if (Binder.getCallingUid() == Process.SYSTEM_UID
501                         || context.checkCallingOrSelfPermission(
502                                 Manifest.permission.INTERACT_ACROSS_USERS)
503                                         == PackageManager.PERMISSION_GRANTED
504                         || context.checkCallingOrSelfPermission(
505                                 Manifest.permission.INTERACT_ACROSS_USERS_FULL)
506                                         == PackageManager.PERMISSION_GRANTED) {
507                     userId = UserHandle.USER_CURRENT;
508                 } else {
509                     userId = context.getUserId();
510                 }
511                 sInstance = new AccessibilityManager(context, null, userId);
512             }
513         }
514         return sInstance;
515     }
516 
517     /**
518      * Create an instance.
519      *
520      * @param context A {@link Context}.
521      * @param service An interface to the backing service.
522      * @param userId User id under which to run.
523      *
524      * @hide
525      */
AccessibilityManager(Context context, IAccessibilityManager service, int userId)526     public AccessibilityManager(Context context, IAccessibilityManager service, int userId) {
527         // Constructor can't be chained because we can't create an instance of an inner class
528         // before calling another constructor.
529         mCallback = new MyCallback();
530         mHandler = new Handler(context.getMainLooper(), mCallback);
531         mUserId = userId;
532         synchronized (mLock) {
533             initialFocusAppearanceLocked(context.getResources());
534             tryConnectToServiceLocked(service);
535         }
536     }
537 
538     /**
539      * Create an instance.
540      *
541      * @param context A {@link Context}.
542      * @param handler The handler to use
543      * @param service An interface to the backing service.
544      * @param userId User id under which to run.
545      * @param serviceConnect {@code true} to connect the service or
546      *                       {@code false} not to connect the service.
547      *
548      * @hide
549      */
550     @VisibleForTesting
AccessibilityManager(Context context, Handler handler, IAccessibilityManager service, int userId, boolean serviceConnect)551     public AccessibilityManager(Context context, Handler handler, IAccessibilityManager service,
552             int userId, boolean serviceConnect) {
553         mCallback = new MyCallback();
554         mHandler = handler;
555         mUserId = userId;
556         synchronized (mLock) {
557             initialFocusAppearanceLocked(context.getResources());
558             if (serviceConnect) {
559                 tryConnectToServiceLocked(service);
560             }
561         }
562     }
563 
564     /**
565      * @hide
566      */
getClient()567     public IAccessibilityManagerClient getClient() {
568         return mClient;
569     }
570 
571     /**
572      * Unregisters the IAccessibilityManagerClient from the backing service
573      * @hide
574      */
removeClient()575     public boolean removeClient() {
576         synchronized (mLock) {
577             IAccessibilityManager service = getServiceLocked();
578             if (service == null) {
579                 return false;
580             }
581             try {
582                 return service.removeClient(mClient, mUserId);
583             } catch (RemoteException re) {
584                 Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
585             }
586         }
587         return false;
588     }
589 
590     /**
591      * @hide
592      */
593     @VisibleForTesting
getCallback()594     public Handler.Callback getCallback() {
595         return mCallback;
596     }
597 
598     /**
599      * Returns if the accessibility in the system is enabled.
600      * <p>
601      * <b>Note:</b> This query is used for sending {@link AccessibilityEvent}s, since events are
602      * only needed if accessibility is on. Avoid changing UI or app behavior based on the state of
603      * accessibility. While well-intentioned, doing this creates brittle, less
604      * well-maintained code that works for some users but not others. Shared code leads to more
605      * equitable experiences and less technical debt.
606      *
607      *<p>
608      * For example, if you want to expose a unique interaction with your app, use
609      * ViewCompat#addAccessibilityAction in AndroidX to make this interaction - ideally
610      * with the same code path used for non-accessibility users - available to accessibility
611      * services. Services can then expose this action in the way best fit for their users.
612      *
613      * @return True if accessibility is enabled, false otherwise.
614      */
isEnabled()615     public boolean isEnabled() {
616         synchronized (mLock) {
617             return mIsEnabled || hasAnyDirectConnection()
618                     || (mAccessibilityPolicy != null && mAccessibilityPolicy.isEnabled(mIsEnabled));
619         }
620     }
621 
622     /**
623      * @see AccessibilityInteractionClient#hasAnyDirectConnection
624      * @hide
625      */
626     @TestApi
hasAnyDirectConnection()627     public boolean hasAnyDirectConnection() {
628         return AccessibilityInteractionClient.hasAnyDirectConnection();
629     }
630 
631     /**
632      * Returns if the touch exploration in the system is enabled.
633      * <p>
634      * <b>Note:</b> This query is used for dispatching hover events, such as
635      * {@link android.view.MotionEvent#ACTION_HOVER_ENTER}, to accessibility services to manage
636      * touch exploration. Avoid changing UI or app behavior based on the state of accessibility.
637      * While well-intentioned, doing this creates brittle, less well-maintained code that works for
638      * som users but not others. Shared code leads to more equitable experiences and less technical
639      * debt.
640      *
641      * @return True if touch exploration is enabled, false otherwise.
642      */
isTouchExplorationEnabled()643     public boolean isTouchExplorationEnabled() {
644         synchronized (mLock) {
645             IAccessibilityManager service = getServiceLocked();
646             if (service == null) {
647                 return false;
648             }
649             return mIsTouchExplorationEnabled;
650         }
651     }
652 
653     /**
654      * Returns if the high text contrast in the system is enabled.
655      * <p>
656      * <strong>Note:</strong> You need to query this only if you application is
657      * doing its own rendering and does not rely on the platform rendering pipeline.
658      * </p>
659      *
660      * @return True if high text contrast is enabled, false otherwise.
661      *
662      * @hide
663      */
664     @UnsupportedAppUsage
isHighTextContrastEnabled()665     public boolean isHighTextContrastEnabled() {
666         synchronized (mLock) {
667             IAccessibilityManager service = getServiceLocked();
668             if (service == null) {
669                 return false;
670             }
671             return mIsHighTextContrastEnabled;
672         }
673     }
674 
675     /**
676      * Sends an {@link AccessibilityEvent}.
677      *
678      * @param event The event to send.
679      *
680      * @throws IllegalStateException if accessibility is not enabled.
681      *
682      * <strong>Note:</strong> The preferred mechanism for sending custom accessibility
683      * events is through calling
684      * {@link android.view.ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)}
685      * instead of this method to allow predecessors to augment/filter events sent by
686      * their descendants.
687      */
sendAccessibilityEvent(AccessibilityEvent event)688     public void sendAccessibilityEvent(AccessibilityEvent event) {
689         final IAccessibilityManager service;
690         final int userId;
691         final AccessibilityEvent dispatchedEvent;
692         synchronized (mLock) {
693             service = getServiceLocked();
694             if (service == null) {
695                 return;
696             }
697             event.setEventTime(SystemClock.uptimeMillis());
698             if (event.getAction() == 0) {
699                 event.setAction(mPerformingAction);
700             }
701             if (mAccessibilityPolicy != null) {
702                 dispatchedEvent = mAccessibilityPolicy.onAccessibilityEvent(event,
703                         mIsEnabled, mRelevantEventTypes);
704                 if (dispatchedEvent == null) {
705                     return;
706                 }
707             } else {
708                 dispatchedEvent = event;
709             }
710             if (!isEnabled()) {
711                 Looper myLooper = Looper.myLooper();
712                 if (myLooper == Looper.getMainLooper()) {
713                     throw new IllegalStateException(
714                             "Accessibility off. Did you forget to check that?");
715                 } else {
716                     // If we're not running on the thread with the main looper, it's possible for
717                     // the state of accessibility to change between checking isEnabled and
718                     // calling this method. So just log the error rather than throwing the
719                     // exception.
720                     Log.e(LOG_TAG, "AccessibilityEvent sent with accessibility disabled");
721                     return;
722                 }
723             }
724             if ((dispatchedEvent.getEventType() & mRelevantEventTypes) == 0) {
725                 if (DEBUG) {
726                     Log.i(LOG_TAG, "Not dispatching irrelevant event: " + dispatchedEvent
727                             + " that is not among "
728                             + AccessibilityEvent.eventTypeToString(mRelevantEventTypes));
729                 }
730                 return;
731             }
732             userId = mUserId;
733         }
734         try {
735             // it is possible that this manager is in the same process as the service but
736             // client using it is called through Binder from another process. Example: MMS
737             // app adds a SMS notification and the NotificationManagerService calls this method
738             final long identityToken = Binder.clearCallingIdentity();
739             try {
740                 service.sendAccessibilityEvent(dispatchedEvent, userId);
741             } finally {
742                 Binder.restoreCallingIdentity(identityToken);
743             }
744             if (DEBUG) {
745                 Log.i(LOG_TAG, dispatchedEvent + " sent");
746             }
747         } catch (RemoteException re) {
748             Log.e(LOG_TAG, "Error during sending " + dispatchedEvent + " ", re);
749         } finally {
750             if (event != dispatchedEvent) {
751                 event.recycle();
752             }
753             dispatchedEvent.recycle();
754         }
755     }
756 
757     /**
758      * Requests feedback interruption from all accessibility services.
759      */
interrupt()760     public void interrupt() {
761         final IAccessibilityManager service;
762         final int userId;
763         synchronized (mLock) {
764             service = getServiceLocked();
765             if (service == null) {
766                 return;
767             }
768             if (!isEnabled()) {
769                 Looper myLooper = Looper.myLooper();
770                 if (myLooper == Looper.getMainLooper()) {
771                     throw new IllegalStateException(
772                             "Accessibility off. Did you forget to check that?");
773                 } else {
774                     // If we're not running on the thread with the main looper, it's possible for
775                     // the state of accessibility to change between checking isEnabled and
776                     // calling this method. So just log the error rather than throwing the
777                     // exception.
778                     Log.e(LOG_TAG, "Interrupt called with accessibility disabled");
779                     return;
780                 }
781             }
782             userId = mUserId;
783         }
784         try {
785             service.interrupt(userId);
786             if (DEBUG) {
787                 Log.i(LOG_TAG, "Requested interrupt from all services");
788             }
789         } catch (RemoteException re) {
790             Log.e(LOG_TAG, "Error while requesting interrupt from all services. ", re);
791         }
792     }
793 
794     /**
795      * Returns the {@link ServiceInfo}s of the installed accessibility services.
796      *
797      * @return An unmodifiable list with {@link ServiceInfo}s.
798      *
799      * @deprecated Use {@link #getInstalledAccessibilityServiceList()}
800      */
801     @Deprecated
getAccessibilityServiceList()802     public List<ServiceInfo> getAccessibilityServiceList() {
803         List<AccessibilityServiceInfo> infos = getInstalledAccessibilityServiceList();
804         List<ServiceInfo> services = new ArrayList<>();
805         final int infoCount = infos.size();
806         for (int i = 0; i < infoCount; i++) {
807             AccessibilityServiceInfo info = infos.get(i);
808             services.add(info.getResolveInfo().serviceInfo);
809         }
810         return Collections.unmodifiableList(services);
811     }
812 
813     /**
814      * Returns the {@link AccessibilityServiceInfo}s of the installed accessibility services.
815      *
816      * @return An unmodifiable list with {@link AccessibilityServiceInfo}s.
817      */
getInstalledAccessibilityServiceList()818     public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList() {
819         final IAccessibilityManager service;
820         final int userId;
821         synchronized (mLock) {
822             service = getServiceLocked();
823             if (service == null) {
824                 return Collections.emptyList();
825             }
826             userId = mUserId;
827         }
828 
829         List<AccessibilityServiceInfo> services = null;
830         try {
831             services = service.getInstalledAccessibilityServiceList(userId).getList();
832             if (DEBUG) {
833                 Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
834             }
835         } catch (RemoteException re) {
836             Log.e(LOG_TAG, "Error while obtaining the installed AccessibilityServices. ", re);
837         }
838         if (mAccessibilityPolicy != null) {
839             services = mAccessibilityPolicy.getInstalledAccessibilityServiceList(services);
840         }
841         if (services != null) {
842             return Collections.unmodifiableList(services);
843         } else {
844             return Collections.emptyList();
845         }
846     }
847 
848     /**
849      * Returns the {@link AccessibilityServiceInfo}s of the enabled accessibility services
850      * for a given feedback type.
851      *
852      * @param feedbackTypeFlags The feedback type flags.
853      * @return An unmodifiable list with {@link AccessibilityServiceInfo}s.
854      *
855      * @see AccessibilityServiceInfo#FEEDBACK_AUDIBLE
856      * @see AccessibilityServiceInfo#FEEDBACK_GENERIC
857      * @see AccessibilityServiceInfo#FEEDBACK_HAPTIC
858      * @see AccessibilityServiceInfo#FEEDBACK_SPOKEN
859      * @see AccessibilityServiceInfo#FEEDBACK_VISUAL
860      * @see AccessibilityServiceInfo#FEEDBACK_BRAILLE
861      */
getEnabledAccessibilityServiceList( int feedbackTypeFlags)862     public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(
863             int feedbackTypeFlags) {
864         final IAccessibilityManager service;
865         final int userId;
866         synchronized (mLock) {
867             service = getServiceLocked();
868             if (service == null) {
869                 return Collections.emptyList();
870             }
871             userId = mUserId;
872         }
873 
874         List<AccessibilityServiceInfo> services = null;
875         try {
876             services = service.getEnabledAccessibilityServiceList(feedbackTypeFlags, userId);
877             if (DEBUG) {
878                 Log.i(LOG_TAG, "Enabled AccessibilityServices " + services);
879             }
880         } catch (RemoteException re) {
881             Log.e(LOG_TAG, "Error while obtaining the enabled AccessibilityServices. ", re);
882         }
883         if (mAccessibilityPolicy != null) {
884             services = mAccessibilityPolicy.getEnabledAccessibilityServiceList(
885                     feedbackTypeFlags, services);
886         }
887         if (services != null) {
888             return Collections.unmodifiableList(services);
889         } else {
890             return Collections.emptyList();
891         }
892     }
893 
894     /**
895      * Returns whether the user must be shown the AccessibilityService warning dialog
896      * before the AccessibilityService (or any shortcut for the service) can be enabled.
897      * @hide
898      */
899     @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
isAccessibilityServiceWarningRequired(@onNull AccessibilityServiceInfo info)900     public boolean isAccessibilityServiceWarningRequired(@NonNull AccessibilityServiceInfo info) {
901         final IAccessibilityManager service;
902         synchronized (mLock) {
903             service = getServiceLocked();
904             if (service == null) {
905                 return true;
906             }
907         }
908         try {
909             return service.isAccessibilityServiceWarningRequired(info);
910         } catch (RemoteException re) {
911             Log.e(LOG_TAG, "Error while checking isAccessibilityServiceWarningRequired: ", re);
912             return true;
913         }
914     }
915 
916     /**
917      * Registers an {@link AccessibilityStateChangeListener} for changes in
918      * the global accessibility state of the system. Equivalent to calling
919      * {@link #addAccessibilityStateChangeListener(AccessibilityStateChangeListener, Handler)}
920      * with a null handler.
921      *
922      * @param listener The listener.
923      * @return Always returns {@code true}.
924      */
addAccessibilityStateChangeListener( @onNull AccessibilityStateChangeListener listener)925     public boolean addAccessibilityStateChangeListener(
926             @NonNull AccessibilityStateChangeListener listener) {
927         addAccessibilityStateChangeListener(listener, null);
928         return true;
929     }
930 
931     /**
932      * Registers an {@link AccessibilityStateChangeListener} for changes in
933      * the global accessibility state of the system. If the listener has already been registered,
934      * the handler used to call it back is updated.
935      *
936      * @param listener The listener.
937      * @param handler The handler on which the listener should be called back, or {@code null}
938      *                for a callback on the process's main handler.
939      */
addAccessibilityStateChangeListener( @onNull AccessibilityStateChangeListener listener, @Nullable Handler handler)940     public void addAccessibilityStateChangeListener(
941             @NonNull AccessibilityStateChangeListener listener, @Nullable Handler handler) {
942         synchronized (mLock) {
943             mAccessibilityStateChangeListeners
944                     .put(listener, (handler == null) ? mHandler : handler);
945         }
946     }
947 
948     /**
949      * Unregisters an {@link AccessibilityStateChangeListener}.
950      *
951      * @param listener The listener.
952      * @return True if the listener was previously registered.
953      */
removeAccessibilityStateChangeListener( @onNull AccessibilityStateChangeListener listener)954     public boolean removeAccessibilityStateChangeListener(
955             @NonNull AccessibilityStateChangeListener listener) {
956         synchronized (mLock) {
957             int index = mAccessibilityStateChangeListeners.indexOfKey(listener);
958             mAccessibilityStateChangeListeners.remove(listener);
959             return (index >= 0);
960         }
961     }
962 
963     /**
964      * Registers a {@link TouchExplorationStateChangeListener} for changes in
965      * the global touch exploration state of the system. Equivalent to calling
966      * {@link #addTouchExplorationStateChangeListener(TouchExplorationStateChangeListener, Handler)}
967      * with a null handler.
968      *
969      * @param listener The listener.
970      * @return Always returns {@code true}.
971      */
addTouchExplorationStateChangeListener( @onNull TouchExplorationStateChangeListener listener)972     public boolean addTouchExplorationStateChangeListener(
973             @NonNull TouchExplorationStateChangeListener listener) {
974         addTouchExplorationStateChangeListener(listener, null);
975         return true;
976     }
977 
978     /**
979      * Registers an {@link TouchExplorationStateChangeListener} for changes in
980      * the global touch exploration state of the system. If the listener has already been
981      * registered, the handler used to call it back is updated.
982      *
983      * @param listener The listener.
984      * @param handler The handler on which the listener should be called back, or {@code null}
985      *                for a callback on the process's main handler.
986      */
addTouchExplorationStateChangeListener( @onNull TouchExplorationStateChangeListener listener, @Nullable Handler handler)987     public void addTouchExplorationStateChangeListener(
988             @NonNull TouchExplorationStateChangeListener listener, @Nullable Handler handler) {
989         synchronized (mLock) {
990             mTouchExplorationStateChangeListeners
991                     .put(listener, (handler == null) ? mHandler : handler);
992         }
993     }
994 
995     /**
996      * Unregisters a {@link TouchExplorationStateChangeListener}.
997      *
998      * @param listener The listener.
999      * @return True if listener was previously registered.
1000      */
removeTouchExplorationStateChangeListener( @onNull TouchExplorationStateChangeListener listener)1001     public boolean removeTouchExplorationStateChangeListener(
1002             @NonNull TouchExplorationStateChangeListener listener) {
1003         synchronized (mLock) {
1004             int index = mTouchExplorationStateChangeListeners.indexOfKey(listener);
1005             mTouchExplorationStateChangeListeners.remove(listener);
1006             return (index >= 0);
1007         }
1008     }
1009 
1010     /**
1011      * Registers a {@link AccessibilityServicesStateChangeListener}.
1012      *
1013      * @param executor The executor.
1014      * @param listener The listener.
1015      */
addAccessibilityServicesStateChangeListener( @onNull @allbackExecutor Executor executor, @NonNull AccessibilityServicesStateChangeListener listener)1016     public void addAccessibilityServicesStateChangeListener(
1017             @NonNull @CallbackExecutor Executor executor,
1018             @NonNull AccessibilityServicesStateChangeListener listener) {
1019         synchronized (mLock) {
1020             mServicesStateChangeListeners.put(listener, executor);
1021         }
1022     }
1023 
1024     /**
1025      * Registers a {@link AccessibilityServicesStateChangeListener}. This will execute a callback on
1026      * the process's main handler.
1027      *
1028      * @param listener The listener.
1029      *
1030      */
addAccessibilityServicesStateChangeListener( @onNull AccessibilityServicesStateChangeListener listener)1031     public void addAccessibilityServicesStateChangeListener(
1032             @NonNull AccessibilityServicesStateChangeListener listener) {
1033         addAccessibilityServicesStateChangeListener(new HandlerExecutor(mHandler), listener);
1034     }
1035 
1036     /**
1037      * Unregisters a {@link AccessibilityServicesStateChangeListener}.
1038      *
1039      * @param listener The listener.
1040      * @return {@code true} if the listener was previously registered.
1041      */
removeAccessibilityServicesStateChangeListener( @onNull AccessibilityServicesStateChangeListener listener)1042     public boolean removeAccessibilityServicesStateChangeListener(
1043             @NonNull AccessibilityServicesStateChangeListener listener) {
1044         synchronized (mLock) {
1045             return mServicesStateChangeListeners.remove(listener) != null;
1046         }
1047     }
1048 
1049     /**
1050      * Whether the current accessibility request comes from an
1051      * {@link AccessibilityService} with the {@link AccessibilityServiceInfo#isAccessibilityTool}
1052      * property set to true.
1053      *
1054      * <p>
1055      * You can use this method inside {@link AccessibilityNodeProvider} to decide how to populate
1056      * your nodes.
1057      * </p>
1058      *
1059      * <p>
1060      * <strong>Note:</strong> The return value is valid only when an {@link AccessibilityNodeInfo}
1061      * request is in progress, can change from one request to another, and has no meaning when a
1062      * request is not in progress.
1063      * </p>
1064      *
1065      * @return True if the current request is from a tool that sets isAccessibilityTool.
1066      */
isRequestFromAccessibilityTool()1067     public boolean isRequestFromAccessibilityTool() {
1068         return mRequestFromAccessibilityTool;
1069     }
1070 
1071     /**
1072      * Specifies whether the current accessibility request comes from an
1073      * {@link AccessibilityService} with the {@link AccessibilityServiceInfo#isAccessibilityTool}
1074      * property set to true.
1075      *
1076      * @hide
1077      */
setRequestFromAccessibilityTool(boolean requestFromAccessibilityTool)1078     public void setRequestFromAccessibilityTool(boolean requestFromAccessibilityTool) {
1079         mRequestFromAccessibilityTool = requestFromAccessibilityTool;
1080     }
1081 
1082     /**
1083      * Registers a {@link AccessibilityRequestPreparer}.
1084      */
addAccessibilityRequestPreparer(AccessibilityRequestPreparer preparer)1085     public void addAccessibilityRequestPreparer(AccessibilityRequestPreparer preparer) {
1086         if (mRequestPreparerLists == null) {
1087             mRequestPreparerLists = new SparseArray<>(1);
1088         }
1089         int id = preparer.getAccessibilityViewId();
1090         List<AccessibilityRequestPreparer> requestPreparerList = mRequestPreparerLists.get(id);
1091         if (requestPreparerList == null) {
1092             requestPreparerList = new ArrayList<>(1);
1093             mRequestPreparerLists.put(id, requestPreparerList);
1094         }
1095         requestPreparerList.add(preparer);
1096     }
1097 
1098     /**
1099      * Unregisters a {@link AccessibilityRequestPreparer}.
1100      */
removeAccessibilityRequestPreparer(AccessibilityRequestPreparer preparer)1101     public void removeAccessibilityRequestPreparer(AccessibilityRequestPreparer preparer) {
1102         if (mRequestPreparerLists == null) {
1103             return;
1104         }
1105         int viewId = preparer.getAccessibilityViewId();
1106         List<AccessibilityRequestPreparer> requestPreparerList = mRequestPreparerLists.get(viewId);
1107         if (requestPreparerList != null) {
1108             requestPreparerList.remove(preparer);
1109             if (requestPreparerList.isEmpty()) {
1110                 mRequestPreparerLists.remove(viewId);
1111             }
1112         }
1113     }
1114 
1115     /**
1116      * Get the recommended timeout for changes to the UI needed by this user. Controls should remain
1117      * on the screen for at least this long to give users time to react. Some users may need
1118      * extra time to review the controls, or to reach them, or to activate assistive technology
1119      * to activate the controls automatically.
1120      * <p>
1121      * Use the combination of content flags to indicate contents of UI. For example, use
1122      * {@code FLAG_CONTENT_ICONS | FLAG_CONTENT_TEXT} for message notification which contains
1123      * icons and text, or use {@code FLAG_CONTENT_TEXT | FLAG_CONTENT_CONTROLS} for button dialog
1124      * which contains text and button controls.
1125      * <p/>
1126      *
1127      * @param originalTimeout The timeout appropriate for users with no accessibility needs.
1128      * @param uiContentFlags The combination of flags {@link #FLAG_CONTENT_ICONS},
1129      *                       {@link #FLAG_CONTENT_TEXT} or {@link #FLAG_CONTENT_CONTROLS} to
1130      *                       indicate the contents of UI.
1131      * @return The recommended UI timeout for the current user in milliseconds.
1132      */
getRecommendedTimeoutMillis(int originalTimeout, @ContentFlag int uiContentFlags)1133     public int getRecommendedTimeoutMillis(int originalTimeout, @ContentFlag int uiContentFlags) {
1134         boolean hasControls = (uiContentFlags & FLAG_CONTENT_CONTROLS) != 0;
1135         boolean hasIconsOrText = (uiContentFlags & FLAG_CONTENT_ICONS) != 0
1136                 || (uiContentFlags & FLAG_CONTENT_TEXT) != 0;
1137         int recommendedTimeout = originalTimeout;
1138         if (hasControls) {
1139             recommendedTimeout = Math.max(recommendedTimeout, mInteractiveUiTimeout);
1140         }
1141         if (hasIconsOrText) {
1142             recommendedTimeout = Math.max(recommendedTimeout, mNonInteractiveUiTimeout);
1143         }
1144         return recommendedTimeout;
1145     }
1146 
1147     /**
1148      * Gets the strokeWidth of the focus rectangle. This value can be set by
1149      * {@link AccessibilityService}.
1150      *
1151      * @return The strokeWidth of the focus rectangle in pixels.
1152      *
1153      */
getAccessibilityFocusStrokeWidth()1154     public int getAccessibilityFocusStrokeWidth() {
1155         synchronized (mLock) {
1156             return mFocusStrokeWidth;
1157         }
1158     }
1159 
1160     /**
1161      * Gets the color of the focus rectangle. This value can be set by
1162      * {@link AccessibilityService}.
1163      *
1164      * @return The color of the focus rectangle.
1165      *
1166      */
getAccessibilityFocusColor()1167     public @ColorInt int getAccessibilityFocusColor() {
1168         synchronized (mLock) {
1169             return mFocusColor;
1170         }
1171     }
1172 
1173     /**
1174      * Gets accessibility interaction connection tracing enabled state.
1175      *
1176      * @hide
1177      */
isA11yInteractionConnectionTraceEnabled()1178     public boolean isA11yInteractionConnectionTraceEnabled() {
1179         synchronized (mLock) {
1180             return ((mAccessibilityTracingState
1181                     & STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_ENABLED) != 0);
1182         }
1183     }
1184 
1185     /**
1186      * Gets accessibility interaction connection callback tracing enabled state.
1187      *
1188      * @hide
1189      */
isA11yInteractionConnectionCBTraceEnabled()1190     public boolean isA11yInteractionConnectionCBTraceEnabled() {
1191         synchronized (mLock) {
1192             return ((mAccessibilityTracingState
1193                     & STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_CB_ENABLED) != 0);
1194         }
1195     }
1196 
1197     /**
1198      * Gets accessibility interaction client tracing enabled state.
1199      *
1200      * @hide
1201      */
isA11yInteractionClientTraceEnabled()1202     public boolean isA11yInteractionClientTraceEnabled() {
1203         synchronized (mLock) {
1204             return ((mAccessibilityTracingState
1205                     & STATE_FLAG_TRACE_A11Y_INTERACTION_CLIENT_ENABLED) != 0);
1206         }
1207     }
1208 
1209     /**
1210      * Gets accessibility service tracing enabled state.
1211      *
1212      * @hide
1213      */
isA11yServiceTraceEnabled()1214     public boolean isA11yServiceTraceEnabled() {
1215         synchronized (mLock) {
1216             return ((mAccessibilityTracingState
1217                     & STATE_FLAG_TRACE_A11Y_SERVICE_ENABLED) != 0);
1218         }
1219     }
1220 
1221     /**
1222      * Get the preparers that are registered for an accessibility ID
1223      *
1224      * @param id The ID of interest
1225      * @return The list of preparers, or {@code null} if there are none.
1226      *
1227      * @hide
1228      */
getRequestPreparersForAccessibilityId(int id)1229     public List<AccessibilityRequestPreparer> getRequestPreparersForAccessibilityId(int id) {
1230         if (mRequestPreparerLists == null) {
1231             return null;
1232         }
1233         return mRequestPreparerLists.get(id);
1234     }
1235 
1236     /**
1237      * Set the currently performing accessibility action in views.
1238      *
1239      * @param actionId the action id of {@link AccessibilityNodeInfo.AccessibilityAction}.
1240      * @hide
1241      */
notifyPerformingAction(int actionId)1242     public void notifyPerformingAction(int actionId) {
1243         mPerformingAction = actionId;
1244     }
1245 
1246     /**
1247      * Get the id of {@link AccessibilityNodeInfo.AccessibilityAction} currently being performed.
1248      *
1249      * @hide
1250      */
getPerformingAction()1251     public int getPerformingAction() {
1252         return mPerformingAction;
1253     }
1254 
1255     /**
1256      * Registers a {@link HighTextContrastChangeListener} for changes in
1257      * the global high text contrast state of the system.
1258      *
1259      * @param listener The listener.
1260      *
1261      * @hide
1262      */
addHighTextContrastStateChangeListener( @onNull HighTextContrastChangeListener listener, @Nullable Handler handler)1263     public void addHighTextContrastStateChangeListener(
1264             @NonNull HighTextContrastChangeListener listener, @Nullable Handler handler) {
1265         synchronized (mLock) {
1266             mHighTextContrastStateChangeListeners
1267                     .put(listener, (handler == null) ? mHandler : handler);
1268         }
1269     }
1270 
1271     /**
1272      * Unregisters a {@link HighTextContrastChangeListener}.
1273      *
1274      * @param listener The listener.
1275      *
1276      * @hide
1277      */
removeHighTextContrastStateChangeListener( @onNull HighTextContrastChangeListener listener)1278     public void removeHighTextContrastStateChangeListener(
1279             @NonNull HighTextContrastChangeListener listener) {
1280         synchronized (mLock) {
1281             mHighTextContrastStateChangeListeners.remove(listener);
1282         }
1283     }
1284 
1285     /**
1286      * Registers a {@link AudioDescriptionRequestedChangeListener}
1287      * for changes in the audio description by default state of the system.
1288      * The value could be read via {@link #isAudioDescriptionRequested}.
1289      *
1290      * @param executor The executor on which the listener should be called back.
1291      * @param listener The listener.
1292      */
addAudioDescriptionRequestedChangeListener( @onNull Executor executor, @NonNull AudioDescriptionRequestedChangeListener listener)1293     public void addAudioDescriptionRequestedChangeListener(
1294             @NonNull Executor executor,
1295             @NonNull AudioDescriptionRequestedChangeListener listener) {
1296         synchronized (mLock) {
1297             mAudioDescriptionRequestedChangeListeners.put(listener, executor);
1298         }
1299     }
1300 
1301     /**
1302      * Unregisters a {@link AudioDescriptionRequestedChangeListener}.
1303      *
1304      * @param listener The listener.
1305      * @return True if listener was previously registered.
1306      */
removeAudioDescriptionRequestedChangeListener( @onNull AudioDescriptionRequestedChangeListener listener)1307     public boolean removeAudioDescriptionRequestedChangeListener(
1308             @NonNull AudioDescriptionRequestedChangeListener listener) {
1309         synchronized (mLock) {
1310             return (mAudioDescriptionRequestedChangeListeners.remove(listener) != null);
1311         }
1312     }
1313 
1314     /**
1315      * Sets the {@link AccessibilityPolicy} controlling this manager.
1316      *
1317      * @param policy The policy.
1318      *
1319      * @hide
1320      */
setAccessibilityPolicy(@ullable AccessibilityPolicy policy)1321     public void setAccessibilityPolicy(@Nullable AccessibilityPolicy policy) {
1322         synchronized (mLock) {
1323             mAccessibilityPolicy = policy;
1324         }
1325     }
1326 
1327     /**
1328      * Check if the accessibility volume stream is active.
1329      *
1330      * @return True if accessibility volume is active (i.e. some service has requested it). False
1331      * otherwise.
1332      * @hide
1333      */
isAccessibilityVolumeStreamActive()1334     public boolean isAccessibilityVolumeStreamActive() {
1335         List<AccessibilityServiceInfo> serviceInfos =
1336                 getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
1337         for (int i = 0; i < serviceInfos.size(); i++) {
1338             if ((serviceInfos.get(i).flags & FLAG_ENABLE_ACCESSIBILITY_VOLUME) != 0) {
1339                 return true;
1340             }
1341         }
1342         return false;
1343     }
1344 
1345     /**
1346      * Report a fingerprint gesture to accessibility. Only available for the system process.
1347      *
1348      * @param keyCode The key code of the gesture
1349      * @return {@code true} if accessibility consumes the event. {@code false} if not.
1350      * @hide
1351      */
sendFingerprintGesture(int keyCode)1352     public boolean sendFingerprintGesture(int keyCode) {
1353         final IAccessibilityManager service;
1354         synchronized (mLock) {
1355             service = getServiceLocked();
1356             if (service == null) {
1357                 return false;
1358             }
1359         }
1360         try {
1361             return service.sendFingerprintGesture(keyCode);
1362         } catch (RemoteException e) {
1363             return false;
1364         }
1365     }
1366 
1367     /**
1368      * Returns accessibility window id from window token. Accessibility window id is the one
1369      * returned from AccessibilityWindowInfo.getId(). Only available for the system process.
1370      *
1371      * @param windowToken Window token to find accessibility window id.
1372      * @return Accessibility window id for the window token.
1373      *   AccessibilityWindowInfo.UNDEFINED_WINDOW_ID if accessibility window id not available for
1374      *   the token.
1375      * @hide
1376      */
1377     @SystemApi
getAccessibilityWindowId(@ullable IBinder windowToken)1378     public int getAccessibilityWindowId(@Nullable IBinder windowToken) {
1379         if (windowToken == null) {
1380             return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
1381         }
1382 
1383         final IAccessibilityManager service;
1384         synchronized (mLock) {
1385             service = getServiceLocked();
1386             if (service == null) {
1387                 return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
1388             }
1389         }
1390         try {
1391             return service.getAccessibilityWindowId(windowToken);
1392         } catch (RemoteException e) {
1393             return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
1394         }
1395     }
1396 
1397     /**
1398      * Associate the connection between the host View and the embedded SurfaceControlViewHost.
1399      *
1400      * @hide
1401      */
associateEmbeddedHierarchy(@onNull IBinder host, @NonNull IBinder embedded)1402     public void associateEmbeddedHierarchy(@NonNull IBinder host, @NonNull IBinder embedded) {
1403         final IAccessibilityManager service;
1404         synchronized (mLock) {
1405             service = getServiceLocked();
1406             if (service == null) {
1407                 return;
1408             }
1409         }
1410         try {
1411             service.associateEmbeddedHierarchy(host, embedded);
1412         } catch (RemoteException e) {
1413             return;
1414         }
1415     }
1416 
1417     /**
1418      * Disassociate the connection between the host View and the embedded SurfaceControlViewHost.
1419      * The given token could be either from host side or embedded side.
1420      *
1421      * @hide
1422      */
disassociateEmbeddedHierarchy(@onNull IBinder token)1423     public void disassociateEmbeddedHierarchy(@NonNull IBinder token) {
1424         if (token == null) {
1425             return;
1426         }
1427         final IAccessibilityManager service;
1428         synchronized (mLock) {
1429             service = getServiceLocked();
1430             if (service == null) {
1431                 return;
1432             }
1433         }
1434         try {
1435             service.disassociateEmbeddedHierarchy(token);
1436         } catch (RemoteException e) {
1437             return;
1438         }
1439     }
1440 
1441     /**
1442      * Sets the current state and notifies listeners, if necessary.
1443      *
1444      * @param stateFlags The state flags.
1445      */
1446     @UnsupportedAppUsage
setStateLocked(int stateFlags)1447     private void setStateLocked(int stateFlags) {
1448         final boolean enabled = (stateFlags & STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
1449         final boolean touchExplorationEnabled =
1450                 (stateFlags & STATE_FLAG_TOUCH_EXPLORATION_ENABLED) != 0;
1451         final boolean highTextContrastEnabled =
1452                 (stateFlags & STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED) != 0;
1453         final boolean audioDescriptionEnabled =
1454                 (stateFlags & STATE_FLAG_AUDIO_DESCRIPTION_BY_DEFAULT_ENABLED) != 0;
1455 
1456         final boolean wasEnabled = isEnabled();
1457         final boolean wasTouchExplorationEnabled = mIsTouchExplorationEnabled;
1458         final boolean wasHighTextContrastEnabled = mIsHighTextContrastEnabled;
1459         final boolean wasAudioDescriptionByDefaultRequested = mIsAudioDescriptionByDefaultRequested;
1460 
1461         // Ensure listeners get current state from isZzzEnabled() calls.
1462         mIsEnabled = enabled;
1463         mIsTouchExplorationEnabled = touchExplorationEnabled;
1464         mIsHighTextContrastEnabled = highTextContrastEnabled;
1465         mIsAudioDescriptionByDefaultRequested = audioDescriptionEnabled;
1466 
1467         if (wasEnabled != isEnabled()) {
1468             notifyAccessibilityStateChanged();
1469         }
1470 
1471         if (wasTouchExplorationEnabled != touchExplorationEnabled) {
1472             notifyTouchExplorationStateChanged();
1473         }
1474 
1475         if (wasHighTextContrastEnabled != highTextContrastEnabled) {
1476             notifyHighTextContrastStateChanged();
1477         }
1478 
1479         if (wasAudioDescriptionByDefaultRequested
1480                 != audioDescriptionEnabled) {
1481             notifyAudioDescriptionbyDefaultStateChanged();
1482         }
1483 
1484         updateAccessibilityTracingState(stateFlags);
1485     }
1486 
1487     /**
1488      * Find an installed service with the specified {@link ComponentName}.
1489      *
1490      * @param componentName The name to match to the service.
1491      *
1492      * @return The info corresponding to the installed service, or {@code null} if no such service
1493      * is installed.
1494      * @hide
1495      */
getInstalledServiceInfoWithComponentName( ComponentName componentName)1496     public AccessibilityServiceInfo getInstalledServiceInfoWithComponentName(
1497             ComponentName componentName) {
1498         final List<AccessibilityServiceInfo> installedServiceInfos =
1499                 getInstalledAccessibilityServiceList();
1500         if ((installedServiceInfos == null) || (componentName == null)) {
1501             return null;
1502         }
1503         for (int i = 0; i < installedServiceInfos.size(); i++) {
1504             if (componentName.equals(installedServiceInfos.get(i).getComponentName())) {
1505                 return installedServiceInfos.get(i);
1506             }
1507         }
1508         return null;
1509     }
1510 
1511     /**
1512      * Adds an accessibility interaction connection interface for a given window.
1513      * @param windowToken The window token to which a connection is added.
1514      * @param leashToken The leash token to which a connection is added.
1515      * @param connection The connection.
1516      *
1517      * @hide
1518      */
addAccessibilityInteractionConnection(IWindow windowToken, IBinder leashToken, String packageName, IAccessibilityInteractionConnection connection)1519     public int addAccessibilityInteractionConnection(IWindow windowToken, IBinder leashToken,
1520             String packageName, IAccessibilityInteractionConnection connection) {
1521         final IAccessibilityManager service;
1522         final int userId;
1523         synchronized (mLock) {
1524             service = getServiceLocked();
1525             if (service == null) {
1526                 return View.NO_ID;
1527             }
1528             userId = mUserId;
1529         }
1530         try {
1531             return service.addAccessibilityInteractionConnection(windowToken, leashToken,
1532                     connection, packageName, userId);
1533         } catch (RemoteException re) {
1534             Log.e(LOG_TAG, "Error while adding an accessibility interaction connection. ", re);
1535         }
1536         return View.NO_ID;
1537     }
1538 
1539     /**
1540      * Removed an accessibility interaction connection interface for a given window.
1541      * @param windowToken The window token to which a connection is removed.
1542      *
1543      * @hide
1544      */
removeAccessibilityInteractionConnection(IWindow windowToken)1545     public void removeAccessibilityInteractionConnection(IWindow windowToken) {
1546         final IAccessibilityManager service;
1547         synchronized (mLock) {
1548             service = getServiceLocked();
1549             if (service == null) {
1550                 return;
1551             }
1552         }
1553         try {
1554             service.removeAccessibilityInteractionConnection(windowToken);
1555         } catch (RemoteException re) {
1556             Log.e(LOG_TAG, "Error while removing an accessibility interaction connection. ", re);
1557         }
1558     }
1559 
1560     /**
1561      * Perform the accessibility shortcut if the caller has permission.
1562      *
1563      * @hide
1564      */
1565     @SystemApi
1566     @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
performAccessibilityShortcut()1567     public void performAccessibilityShortcut() {
1568         performAccessibilityShortcut(null);
1569     }
1570 
1571     /**
1572      * Perform the accessibility shortcut for the given target which is assigned to the shortcut.
1573      *
1574      * @param targetName The flattened {@link ComponentName} string or the class name of a system
1575      *        class implementing a supported accessibility feature, or {@code null} if there's no
1576      *        specified target.
1577      * @hide
1578      */
1579     @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
performAccessibilityShortcut(@ullable String targetName)1580     public void performAccessibilityShortcut(@Nullable String targetName) {
1581         final IAccessibilityManager service;
1582         synchronized (mLock) {
1583             service = getServiceLocked();
1584             if (service == null) {
1585                 return;
1586             }
1587         }
1588         try {
1589             service.performAccessibilityShortcut(targetName);
1590         } catch (RemoteException re) {
1591             Log.e(LOG_TAG, "Error performing accessibility shortcut. ", re);
1592         }
1593     }
1594 
1595     /**
1596      * Turns on or off a shortcut type of the accessibility features. The shortcut type is one
1597      * of the shortcut defined in the {@link ShortcutConstants.USER_SHORTCUT_TYPES}.
1598      *
1599      * @throws SecurityException if the app does not hold the
1600      *                           {@link Manifest.permission#MANAGE_ACCESSIBILITY} permission
1601      * @hide
1602      */
1603     @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
enableShortcutsForTargets(boolean enable, @ShortcutConstants.UserShortcutType int shortcutTypes, @NonNull Set<String> targets, @UserIdInt int userId)1604     public void enableShortcutsForTargets(boolean enable,
1605             @ShortcutConstants.UserShortcutType int shortcutTypes, @NonNull Set<String> targets,
1606             @UserIdInt int userId) {
1607         final IAccessibilityManager service;
1608         synchronized (mLock) {
1609             service = getServiceLocked();
1610             if (service == null) {
1611                 return;
1612             }
1613         }
1614         try {
1615             service.enableShortcutsForTargets(
1616                     enable, shortcutTypes, targets.stream().toList(), userId);
1617         } catch (RemoteException re) {
1618             throw re.rethrowFromSystemServer();
1619         }
1620     }
1621 
1622     /**
1623      * Returns accessibility feature's component and the provided tile map. This includes the
1624      * TileService provided by the AccessibilityService or Accessibility Activity and the tile
1625      * component provided by the framework's feature.
1626      *
1627      * @return a map of a feature's component name, and its provided tile's component name. The
1628      * returned map's keys and values are not null. If a feature doesn't provide a tile, it won't
1629      * have an entry in this map.
1630      * @hide
1631      * @see ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE
1632      */
1633     @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
1634     @NonNull
getA11yFeatureToTileMap(@serIdInt int userId)1635     public Map<ComponentName, ComponentName> getA11yFeatureToTileMap(@UserIdInt int userId) {
1636         final IAccessibilityManager service;
1637         Map<ComponentName, ComponentName> a11yFeatureToTileMap = new ArrayMap<>();
1638         synchronized (mLock) {
1639             service = getServiceLocked();
1640             if (service == null) {
1641                 return a11yFeatureToTileMap;
1642             }
1643         }
1644         try {
1645             Bundle a11yFeatureToTile = service.getA11yFeatureToTileMap(userId);
1646             for (String key : a11yFeatureToTile.keySet()) {
1647                 ComponentName feature = ComponentName.unflattenFromString(key);
1648                 if (feature == null) {
1649                     continue;
1650                 }
1651                 ComponentName tileService = a11yFeatureToTile.getParcelable(key,
1652                         ComponentName.class);
1653                 if (tileService != null) {
1654                     a11yFeatureToTileMap.put(feature, tileService);
1655                 }
1656             }
1657         } catch (RemoteException re) {
1658             throw re.rethrowFromSystemServer();
1659         }
1660         return a11yFeatureToTileMap;
1661     }
1662 
1663     /**
1664      * Register the provided {@link RemoteAction} with the given actionId
1665      * <p>
1666      * To perform established system actions, an accessibility service uses the GLOBAL_ACTION
1667      * constants in {@link android.accessibilityservice.AccessibilityService}. To provide a
1668      * customized implementation for one of these actions, the id of the registered system action
1669      * must match that of the corresponding GLOBAL_ACTION constant. For example, to register a
1670      * Back action, {@code actionId} must be
1671      * {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_BACK}
1672      * </p>
1673      * @param action The remote action to be registered with the given actionId as system action.
1674      * @param actionId The id uniquely identify the system action.
1675      * @hide
1676      */
1677     @SystemApi
1678     @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
registerSystemAction(@onNull RemoteAction action, int actionId)1679     public void registerSystemAction(@NonNull RemoteAction action, int actionId) {
1680         final IAccessibilityManager service;
1681         synchronized (mLock) {
1682             service = getServiceLocked();
1683             if (service == null) {
1684                 return;
1685             }
1686         }
1687         try {
1688             service.registerSystemAction(action, actionId);
1689 
1690             if (DEBUG) {
1691                 Log.i(LOG_TAG, "System action " + action.getTitle() + " is registered.");
1692             }
1693         } catch (RemoteException re) {
1694             Log.e(LOG_TAG, "Error registering system action " + action.getTitle() + " ", re);
1695         }
1696     }
1697 
1698    /**
1699      * Unregister a system action with the given actionId
1700      *
1701      * @param actionId The id uniquely identify the system action to be unregistered.
1702      * @hide
1703      */
1704     @SystemApi
1705     @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
unregisterSystemAction(int actionId)1706     public void unregisterSystemAction(int actionId) {
1707         final IAccessibilityManager service;
1708         synchronized (mLock) {
1709             service = getServiceLocked();
1710             if (service == null) {
1711                 return;
1712             }
1713         }
1714         try {
1715             service.unregisterSystemAction(actionId);
1716 
1717             if (DEBUG) {
1718                 Log.i(LOG_TAG, "System action with actionId " + actionId + " is unregistered.");
1719             }
1720         } catch (RemoteException re) {
1721             Log.e(LOG_TAG, "Error unregistering system action with actionId " + actionId + " ", re);
1722         }
1723     }
1724 
1725     /**
1726      * Notifies that the accessibility button in the system's navigation area has been clicked
1727      *
1728      * @param displayId The logical display id.
1729      * @hide
1730      */
1731     @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE)
notifyAccessibilityButtonClicked(int displayId)1732     public void notifyAccessibilityButtonClicked(int displayId) {
1733         notifyAccessibilityButtonClicked(displayId, null);
1734     }
1735 
1736     /**
1737      * Perform the accessibility button for the given target which is assigned to the button.
1738      *
1739      * @param displayId displayId The logical display id.
1740      * @param targetName The flattened {@link ComponentName} string or the class name of a system
1741      *        class implementing a supported accessibility feature, or {@code null} if there's no
1742      *        specified target.
1743      * @hide
1744      */
1745     @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE)
notifyAccessibilityButtonClicked(int displayId, @Nullable String targetName)1746     public void notifyAccessibilityButtonClicked(int displayId, @Nullable String targetName) {
1747         final IAccessibilityManager service;
1748         synchronized (mLock) {
1749             service = getServiceLocked();
1750             if (service == null) {
1751                 return;
1752             }
1753         }
1754         try {
1755             service.notifyAccessibilityButtonClicked(displayId, targetName);
1756         } catch (RemoteException re) {
1757             Log.e(LOG_TAG, "Error while dispatching accessibility button click", re);
1758         }
1759     }
1760 
1761     /**
1762      * Notifies that the visibility of the accessibility button in the system's navigation area
1763      * has changed.
1764      *
1765      * @param shown {@code true} if the accessibility button is visible within the system
1766      *                  navigation area, {@code false} otherwise
1767      * @hide
1768      */
notifyAccessibilityButtonVisibilityChanged(boolean shown)1769     public void notifyAccessibilityButtonVisibilityChanged(boolean shown) {
1770         final IAccessibilityManager service;
1771         synchronized (mLock) {
1772             service = getServiceLocked();
1773             if (service == null) {
1774                 return;
1775             }
1776         }
1777         try {
1778             service.notifyAccessibilityButtonVisibilityChanged(shown);
1779         } catch (RemoteException re) {
1780             Log.e(LOG_TAG, "Error while dispatching accessibility button visibility change", re);
1781         }
1782     }
1783 
1784     /**
1785      * Set an IAccessibilityInteractionConnection to replace the actions of a picture-in-picture
1786      * window. Intended for use by the System UI only.
1787      *
1788      * @param connection The connection to handle the actions. Set to {@code null} to avoid
1789      * affecting the actions.
1790      *
1791      * @hide
1792      */
setPictureInPictureActionReplacingConnection( @ullable IAccessibilityInteractionConnection connection)1793     public void setPictureInPictureActionReplacingConnection(
1794             @Nullable IAccessibilityInteractionConnection connection) {
1795         final IAccessibilityManager service;
1796         synchronized (mLock) {
1797             service = getServiceLocked();
1798             if (service == null) {
1799                 return;
1800             }
1801         }
1802         try {
1803             service.setPictureInPictureActionReplacingConnection(connection);
1804         } catch (RemoteException re) {
1805             Log.e(LOG_TAG, "Error setting picture in picture action replacement", re);
1806         }
1807     }
1808 
1809     /**
1810      * Returns the list of shortcut target names currently assigned to the given shortcut.
1811      *
1812      * @param shortcutType The shortcut type.
1813      * @return The list of shortcut target names.
1814      * @hide
1815      */
1816     @TestApi
1817     @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
1818     @NonNull
getAccessibilityShortcutTargets( @hortcutConstants.UserShortcutType int shortcutType)1819     public List<String> getAccessibilityShortcutTargets(
1820             @ShortcutConstants.UserShortcutType int shortcutType) {
1821         final IAccessibilityManager service;
1822         synchronized (mLock) {
1823             service = getServiceLocked();
1824         }
1825         if (service != null) {
1826             try {
1827                 return service.getAccessibilityShortcutTargets(shortcutType);
1828             } catch (RemoteException re) {
1829                 re.rethrowFromSystemServer();
1830             }
1831         }
1832         return Collections.emptyList();
1833     }
1834 
1835     /**
1836      * Returns the {@link AccessibilityShortcutInfo}s of the installed accessibility shortcut
1837      * targets, for specific user.
1838      *
1839      * @param context The context of the application.
1840      * @param userId The user id.
1841      * @return A list with {@link AccessibilityShortcutInfo}s.
1842      * @hide
1843      */
1844     @NonNull
getInstalledAccessibilityShortcutListAsUser( @onNull Context context, @UserIdInt int userId)1845     public List<AccessibilityShortcutInfo> getInstalledAccessibilityShortcutListAsUser(
1846             @NonNull Context context, @UserIdInt int userId) {
1847         final List<AccessibilityShortcutInfo> shortcutInfos = new ArrayList<>();
1848         final int flags = PackageManager.GET_ACTIVITIES
1849                 | PackageManager.GET_META_DATA
1850                 | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
1851                 | PackageManager.MATCH_DIRECT_BOOT_AWARE
1852                 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
1853         final Intent actionMain = new Intent(Intent.ACTION_MAIN);
1854         actionMain.addCategory(Intent.CATEGORY_ACCESSIBILITY_SHORTCUT_TARGET);
1855 
1856         final PackageManager packageManager = context.getPackageManager();
1857         final List<ResolveInfo> installedShortcutList =
1858                 packageManager.queryIntentActivitiesAsUser(actionMain, flags, userId);
1859         for (int i = 0; i < installedShortcutList.size(); i++) {
1860             final AccessibilityShortcutInfo shortcutInfo =
1861                     getShortcutInfo(context, installedShortcutList.get(i));
1862             if (shortcutInfo != null) {
1863                 shortcutInfos.add(shortcutInfo);
1864             }
1865         }
1866         return shortcutInfos;
1867     }
1868 
1869     /**
1870      * Returns an {@link AccessibilityShortcutInfo} according to the given {@link ResolveInfo} of
1871      * an activity.
1872      *
1873      * @param context The context of the application.
1874      * @param resolveInfo The resolve info of an activity.
1875      * @return The AccessibilityShortcutInfo.
1876      */
1877     @Nullable
getShortcutInfo(@onNull Context context, @NonNull ResolveInfo resolveInfo)1878     private AccessibilityShortcutInfo getShortcutInfo(@NonNull Context context,
1879             @NonNull ResolveInfo resolveInfo) {
1880         final ActivityInfo activityInfo = resolveInfo.activityInfo;
1881         if (activityInfo == null || activityInfo.metaData == null
1882                 || activityInfo.metaData.getInt(AccessibilityShortcutInfo.META_DATA) == 0) {
1883             return null;
1884         }
1885         try {
1886             return new AccessibilityShortcutInfo(context, activityInfo);
1887         } catch (XmlPullParserException | IOException exp) {
1888             Log.e(LOG_TAG, "Error while initializing AccessibilityShortcutInfo", exp);
1889         }
1890         return null;
1891     }
1892 
1893     /**
1894      *
1895      * Sets an {@link IMagnificationConnection} that manipulates magnification in SystemUI.
1896      *
1897      * @param connection The connection that manipulates magnification in SystemUI.
1898      * @hide
1899      */
setMagnificationConnection(@ullable IMagnificationConnection connection)1900     public void setMagnificationConnection(@Nullable
1901             IMagnificationConnection connection) {
1902         final IAccessibilityManager service;
1903         synchronized (mLock) {
1904             service = getServiceLocked();
1905             if (service == null) {
1906                 return;
1907             }
1908         }
1909         try {
1910             service.setMagnificationConnection(connection);
1911         } catch (RemoteException re) {
1912             Log.e(LOG_TAG, "Error setting magnification connection", re);
1913         }
1914     }
1915 
1916     /**
1917      * Determines if users want to select sound track with audio description by default.
1918      * <p>
1919      * Audio description, also referred to as a video description, described video, or
1920      * more precisely called a visual description, is a form of narration used to provide
1921      * information surrounding key visual elements in a media work for the benefit of
1922      * blind and visually impaired consumers.
1923      * </p>
1924      * <p>
1925      * The method provides the preference value to content provider apps to select the
1926      * default sound track during playing a video or movie.
1927      * </p>
1928      * <p>
1929      * Add listener to detect the state change via
1930      * {@link #addAudioDescriptionRequestedChangeListener}
1931      * </p>
1932      * @return {@code true} if the audio description is enabled, {@code false} otherwise.
1933      */
isAudioDescriptionRequested()1934     public boolean isAudioDescriptionRequested() {
1935         synchronized (mLock) {
1936             IAccessibilityManager service = getServiceLocked();
1937             if (service == null) {
1938                 return false;
1939             }
1940             return mIsAudioDescriptionByDefaultRequested;
1941         }
1942     }
1943 
1944     /**
1945      * Sets the system audio caption enabled state.
1946      *
1947      * @param isEnabled The system audio captioning enabled state.
1948      * @param userId The user Id.
1949      * @hide
1950      */
setSystemAudioCaptioningEnabled(boolean isEnabled, int userId)1951     public void setSystemAudioCaptioningEnabled(boolean isEnabled, int userId) {
1952         final IAccessibilityManager service;
1953         synchronized (mLock) {
1954             service = getServiceLocked();
1955             if (service == null) {
1956                 return;
1957             }
1958         }
1959         try {
1960             service.setSystemAudioCaptioningEnabled(isEnabled, userId);
1961         } catch (RemoteException re) {
1962             throw re.rethrowFromSystemServer();
1963         }
1964     }
1965 
1966     /**
1967      * Gets the system audio caption UI enabled state.
1968      *
1969      * @param userId The user Id.
1970      * @return the system audio caption UI enabled state.
1971      * @hide
1972      */
isSystemAudioCaptioningUiEnabled(int userId)1973     public boolean isSystemAudioCaptioningUiEnabled(int userId) {
1974         final IAccessibilityManager service;
1975         synchronized (mLock) {
1976             service = getServiceLocked();
1977             if (service == null) {
1978                 return false;
1979             }
1980         }
1981         try {
1982             return service.isSystemAudioCaptioningUiEnabled(userId);
1983         } catch (RemoteException re) {
1984             throw re.rethrowFromSystemServer();
1985         }
1986     }
1987 
1988     /**
1989      * Sets the system audio caption UI enabled state.
1990      *
1991      * @param isEnabled The system audio captioning UI enabled state.
1992      * @param userId The user Id.
1993      * @hide
1994      */
setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId)1995     public void setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId) {
1996         final IAccessibilityManager service;
1997         synchronized (mLock) {
1998             service = getServiceLocked();
1999             if (service == null) {
2000                 return;
2001             }
2002         }
2003         try {
2004             service.setSystemAudioCaptioningUiEnabled(isEnabled, userId);
2005         } catch (RemoteException re) {
2006             throw re.rethrowFromSystemServer();
2007         }
2008     }
2009 
2010 
2011     /**
2012      * Sets the {@link AccessibilityWindowAttributes} to the window associated with the given
2013      * window id.
2014      *
2015      * @param displayId The display id of the window.
2016      * @param windowId  The id of the window.
2017      * @param attributes The accessibility window attributes.
2018      * @hide
2019      */
setAccessibilityWindowAttributes(int displayId, int windowId, AccessibilityWindowAttributes attributes)2020     public void setAccessibilityWindowAttributes(int displayId, int windowId,
2021             AccessibilityWindowAttributes attributes) {
2022         final IAccessibilityManager service;
2023         synchronized (mLock) {
2024             service = getServiceLocked();
2025             if (service == null) {
2026                 return;
2027             }
2028         }
2029         try {
2030             service.setAccessibilityWindowAttributes(displayId, windowId, mUserId, attributes);
2031         } catch (RemoteException re) {
2032             re.rethrowFromSystemServer();
2033         }
2034     }
2035 
2036     /**
2037      * Registers an {@link AccessibilityDisplayProxy}, so this proxy can access UI content specific
2038      * to its display.
2039      *
2040      * @param proxy the {@link AccessibilityDisplayProxy} to register.
2041      * @return {@code true} if the proxy is successfully registered.
2042      *
2043      * @throws IllegalArgumentException if the proxy's display is not currently tracked by a11y, is
2044      * {@link android.view.Display#DEFAULT_DISPLAY}, is or lower than
2045      * {@link android.view.Display#INVALID_DISPLAY}, or is already being proxy-ed.
2046      *
2047      * @throws SecurityException if the app does not hold the
2048      * {@link Manifest.permission#MANAGE_ACCESSIBILITY} permission or the
2049      * {@link Manifest.permission#CREATE_VIRTUAL_DEVICE} permission.
2050      *
2051      * @hide
2052      */
2053     @SystemApi
2054     @RequiresPermission(allOf = {Manifest.permission.MANAGE_ACCESSIBILITY,
2055             Manifest.permission.CREATE_VIRTUAL_DEVICE})
registerDisplayProxy(@onNull AccessibilityDisplayProxy proxy)2056     public boolean registerDisplayProxy(@NonNull AccessibilityDisplayProxy proxy) {
2057         final IAccessibilityManager service;
2058         synchronized (mLock) {
2059             service = getServiceLocked();
2060             if (service == null) {
2061                 return false;
2062             }
2063         }
2064 
2065         try {
2066             return service.registerProxyForDisplay(proxy.mServiceClient, proxy.getDisplayId());
2067         }  catch (RemoteException re) {
2068             throw re.rethrowFromSystemServer();
2069         }
2070     }
2071 
2072     /**
2073      * Unregisters an {@link AccessibilityDisplayProxy}.
2074      *
2075      * @return {@code true} if the proxy is successfully unregistered.
2076      *
2077      * @throws SecurityException if the app does not hold the
2078      * {@link Manifest.permission#MANAGE_ACCESSIBILITY} permission or the
2079      * {@link Manifest.permission#CREATE_VIRTUAL_DEVICE} permission.
2080      *
2081      * @hide
2082      */
2083     @SystemApi
2084     @RequiresPermission(allOf = {Manifest.permission.MANAGE_ACCESSIBILITY,
2085             Manifest.permission.CREATE_VIRTUAL_DEVICE})
unregisterDisplayProxy(@onNull AccessibilityDisplayProxy proxy)2086     public boolean unregisterDisplayProxy(@NonNull AccessibilityDisplayProxy proxy)  {
2087         final IAccessibilityManager service;
2088         synchronized (mLock) {
2089             service = getServiceLocked();
2090             if (service == null) {
2091                 return false;
2092             }
2093         }
2094         try {
2095             return service.unregisterProxyForDisplay(proxy.getDisplayId());
2096         } catch (RemoteException re) {
2097             throw re.rethrowFromSystemServer();
2098         }
2099     }
2100 
2101     /**
2102      * Start sequence (infinite) type of flash notification. Use {@code Context} to retrieve the
2103      * package name as the identifier of this flash notification.
2104      * The notification can be cancelled later by calling {@link #stopFlashNotificationSequence}
2105      * with same {@code Context}.
2106      * If the binder associated with this {@link AccessibilityManager} instance dies then the
2107      * sequence will stop automatically. It is strongly recommended to call
2108      * {@link #stopFlashNotificationSequence} within a reasonable amount of time after calling
2109      * this method.
2110      *
2111      * @param context The context in which this manager operates.
2112      * @param reason The triggering reason of flash notification.
2113      * @return {@code true} if flash notification works properly.
2114      * @hide
2115      */
2116     @FlaggedApi(Flags.FLAG_FLASH_NOTIFICATION_SYSTEM_API)
2117     @TestApi
2118     @SystemApi(client = MODULE_LIBRARIES)
startFlashNotificationSequence(@onNull Context context, @FlashNotificationReason int reason)2119     public boolean startFlashNotificationSequence(@NonNull Context context,
2120             @FlashNotificationReason int reason) {
2121         final IAccessibilityManager service;
2122         synchronized (mLock) {
2123             service = getServiceLocked();
2124             if (service == null) {
2125                 return false;
2126             }
2127         }
2128 
2129         try {
2130             return service.startFlashNotificationSequence(context.getOpPackageName(),
2131                     reason, mBinder);
2132         } catch (RemoteException re) {
2133             Log.e(LOG_TAG, "Error while start flash notification sequence", re);
2134             return false;
2135         }
2136     }
2137 
2138     /**
2139      * Stop sequence (infinite) type of flash notification. The flash notification with the
2140      * package name retrieved from {@code Context} as identifier will be stopped if exist.
2141      * It is strongly recommended to call this method within a reasonable amount of time after
2142      * calling {@link #startFlashNotificationSequence} method.
2143      *
2144      * @param context The context in which this manager operates.
2145      * @return {@code true} if flash notification stops properly.
2146      * @hide
2147      */
2148     @FlaggedApi(Flags.FLAG_FLASH_NOTIFICATION_SYSTEM_API)
2149     @TestApi
2150     @SystemApi(client = MODULE_LIBRARIES)
stopFlashNotificationSequence(@onNull Context context)2151     public boolean stopFlashNotificationSequence(@NonNull Context context) {
2152         final IAccessibilityManager service;
2153         synchronized (mLock) {
2154             service = getServiceLocked();
2155             if (service == null) {
2156                 return false;
2157             }
2158         }
2159 
2160         try {
2161             return service.stopFlashNotificationSequence(context.getOpPackageName());
2162         } catch (RemoteException re) {
2163             Log.e(LOG_TAG, "Error while stop flash notification sequence", re);
2164             return false;
2165         }
2166     }
2167 
2168     /**
2169      * Start event (finite) type of flash notification.
2170      *
2171      * @param context The context in which this manager operates.
2172      * @param reason The triggering reason of flash notification.
2173      * @param reasonPkg The package that trigger the flash notification.
2174      * @return {@code true} if flash notification works properly.
2175      * @hide
2176      */
startFlashNotificationEvent(@onNull Context context, @FlashNotificationReason int reason, @Nullable String reasonPkg)2177     public boolean startFlashNotificationEvent(@NonNull Context context,
2178             @FlashNotificationReason int reason, @Nullable String reasonPkg) {
2179         final IAccessibilityManager service;
2180         synchronized (mLock) {
2181             service = getServiceLocked();
2182             if (service == null) {
2183                 return false;
2184             }
2185         }
2186 
2187         try {
2188             return service.startFlashNotificationEvent(context.getOpPackageName(),
2189                     reason, reasonPkg);
2190         } catch (RemoteException re) {
2191             Log.e(LOG_TAG, "Error while start flash notification event", re);
2192             return false;
2193         }
2194     }
2195 
2196     /**
2197      * Determines if the accessibility target is allowed.
2198      *
2199      * @param packageName The name of the application attempting to perform the operation.
2200      * @param uid The user id of the application attempting to perform the operation.
2201      * @param userId The id of the user for whom to perform the operation.
2202      * @return {@code true} the accessibility target is allowed.
2203      * @hide
2204      */
isAccessibilityTargetAllowed(String packageName, int uid, int userId)2205     public boolean isAccessibilityTargetAllowed(String packageName, int uid, int userId) {
2206         final IAccessibilityManager service;
2207         synchronized (mLock) {
2208             service = getServiceLocked();
2209             if (service == null) {
2210                 return false;
2211             }
2212         }
2213 
2214         try {
2215             return service.isAccessibilityTargetAllowed(packageName, uid, userId);
2216         } catch (RemoteException re) {
2217             Log.e(LOG_TAG, "Error while check accessibility target status", re);
2218             return false;
2219         }
2220     }
2221 
2222     /**
2223      * Sends restricted dialog intent if the accessibility target is disallowed.
2224      *
2225      * @param packageName The name of the application attempting to perform the operation.
2226      * @param uid The user id of the application attempting to perform the operation.
2227      * @param userId The id of the user for whom to perform the operation.
2228      * @return {@code true} if the restricted dialog is shown.
2229      * @hide
2230      */
sendRestrictedDialogIntent(String packageName, int uid, int userId)2231     public boolean sendRestrictedDialogIntent(String packageName, int uid, int userId) {
2232         final IAccessibilityManager service;
2233         synchronized (mLock) {
2234             service = getServiceLocked();
2235             if (service == null) {
2236                 return false;
2237             }
2238         }
2239 
2240         try {
2241             return service.sendRestrictedDialogIntent(packageName, uid, userId);
2242         } catch (RemoteException re) {
2243             Log.e(LOG_TAG, "Error while show restricted dialog", re);
2244             return false;
2245         }
2246     }
2247 
getServiceLocked()2248     private IAccessibilityManager getServiceLocked() {
2249         if (mService == null) {
2250             tryConnectToServiceLocked(null);
2251         }
2252         return mService;
2253     }
2254 
tryConnectToServiceLocked(IAccessibilityManager service)2255     private void tryConnectToServiceLocked(IAccessibilityManager service) {
2256         if (service == null) {
2257             IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
2258             if (iBinder == null) {
2259                 return;
2260             }
2261             service = IAccessibilityManager.Stub.asInterface(iBinder);
2262         }
2263 
2264         try {
2265             final long userStateAndRelevantEvents = service.addClient(mClient, mUserId);
2266             setStateLocked(IntPair.first(userStateAndRelevantEvents));
2267             mRelevantEventTypes = IntPair.second(userStateAndRelevantEvents);
2268             updateUiTimeout(service.getRecommendedTimeoutMillis());
2269             updateFocusAppearanceLocked(service.getFocusStrokeWidth(), service.getFocusColor());
2270             mService = service;
2271         } catch (RemoteException re) {
2272             Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
2273         }
2274     }
2275 
2276     /**
2277      * Notifies the registered {@link AccessibilityStateChangeListener}s.
2278      *
2279      * Note: this method notifies only the listeners of this single instance.
2280      * AccessibilityManagerService is responsible for calling this method on all of
2281      * its AccessibilityManager clients in order to notify all listeners.
2282      * @hide
2283      */
notifyAccessibilityStateChanged()2284     public void notifyAccessibilityStateChanged() {
2285         final boolean isEnabled;
2286         final ArrayMap<AccessibilityStateChangeListener, Handler> listeners;
2287         synchronized (mLock) {
2288             if (mAccessibilityStateChangeListeners.isEmpty()) {
2289                 return;
2290             }
2291             isEnabled = isEnabled();
2292             listeners = new ArrayMap<>(mAccessibilityStateChangeListeners);
2293         }
2294 
2295         final int numListeners = listeners.size();
2296         for (int i = 0; i < numListeners; i++) {
2297             final AccessibilityStateChangeListener listener = listeners.keyAt(i);
2298             listeners.valueAt(i).post(() ->
2299                     listener.onAccessibilityStateChanged(isEnabled));
2300         }
2301     }
2302 
2303     /**
2304      * Notifies the registered {@link TouchExplorationStateChangeListener}s.
2305      */
notifyTouchExplorationStateChanged()2306     private void notifyTouchExplorationStateChanged() {
2307         final boolean isTouchExplorationEnabled;
2308         final ArrayMap<TouchExplorationStateChangeListener, Handler> listeners;
2309         synchronized (mLock) {
2310             if (mTouchExplorationStateChangeListeners.isEmpty()) {
2311                 return;
2312             }
2313             isTouchExplorationEnabled = mIsTouchExplorationEnabled;
2314             listeners = new ArrayMap<>(mTouchExplorationStateChangeListeners);
2315         }
2316 
2317         final int numListeners = listeners.size();
2318         for (int i = 0; i < numListeners; i++) {
2319             final TouchExplorationStateChangeListener listener = listeners.keyAt(i);
2320             listeners.valueAt(i).post(() ->
2321                     listener.onTouchExplorationStateChanged(isTouchExplorationEnabled));
2322         }
2323     }
2324 
2325     /**
2326      * Notifies the registered {@link HighTextContrastChangeListener}s.
2327      */
notifyHighTextContrastStateChanged()2328     private void notifyHighTextContrastStateChanged() {
2329         final boolean isHighTextContrastEnabled;
2330         final ArrayMap<HighTextContrastChangeListener, Handler> listeners;
2331         synchronized (mLock) {
2332             if (mHighTextContrastStateChangeListeners.isEmpty()) {
2333                 return;
2334             }
2335             isHighTextContrastEnabled = mIsHighTextContrastEnabled;
2336             listeners = new ArrayMap<>(mHighTextContrastStateChangeListeners);
2337         }
2338 
2339         final int numListeners = listeners.size();
2340         for (int i = 0; i < numListeners; i++) {
2341             final HighTextContrastChangeListener listener = listeners.keyAt(i);
2342             listeners.valueAt(i).post(() ->
2343                     listener.onHighTextContrastStateChanged(isHighTextContrastEnabled));
2344         }
2345     }
2346 
2347     /**
2348      * Notifies the registered {@link AudioDescriptionStateChangeListener}s.
2349      */
notifyAudioDescriptionbyDefaultStateChanged()2350     private void notifyAudioDescriptionbyDefaultStateChanged() {
2351         final boolean isAudioDescriptionByDefaultRequested;
2352         final ArrayMap<AudioDescriptionRequestedChangeListener, Executor> listeners;
2353         synchronized (mLock) {
2354             if (mAudioDescriptionRequestedChangeListeners.isEmpty()) {
2355                 return;
2356             }
2357             isAudioDescriptionByDefaultRequested = mIsAudioDescriptionByDefaultRequested;
2358             listeners = new ArrayMap<>(mAudioDescriptionRequestedChangeListeners);
2359         }
2360 
2361         final int numListeners = listeners.size();
2362         for (int i = 0; i < numListeners; i++) {
2363             final AudioDescriptionRequestedChangeListener listener = listeners.keyAt(i);
2364             listeners.valueAt(i).execute(() ->
2365                     listener.onAudioDescriptionRequestedChanged(
2366                         isAudioDescriptionByDefaultRequested));
2367         }
2368     }
2369 
2370     /**
2371      * Update mAccessibilityTracingState.
2372      */
updateAccessibilityTracingState(int stateFlag)2373     private void updateAccessibilityTracingState(int stateFlag) {
2374         synchronized (mLock) {
2375             mAccessibilityTracingState = stateFlag;
2376         }
2377     }
2378 
2379     /**
2380      * Update interactive and non-interactive UI timeout.
2381      *
2382      * @param uiTimeout A pair of {@code int}s. First integer for interactive one, and second
2383      *                  integer for non-interactive one.
2384      */
updateUiTimeout(long uiTimeout)2385     private void updateUiTimeout(long uiTimeout) {
2386         mInteractiveUiTimeout = IntPair.first(uiTimeout);
2387         mNonInteractiveUiTimeout = IntPair.second(uiTimeout);
2388     }
2389 
2390     /**
2391      * Updates the stroke width and color of the focus rectangle.
2392      *
2393      * @param strokeWidth The strokeWidth of the focus rectangle.
2394      * @param color The color of the focus rectangle.
2395      */
updateFocusAppearanceLocked(int strokeWidth, int color)2396     private void updateFocusAppearanceLocked(int strokeWidth, int color) {
2397         if (mFocusStrokeWidth == strokeWidth && mFocusColor == color) {
2398             return;
2399         }
2400         mFocusStrokeWidth = strokeWidth;
2401         mFocusColor = color;
2402     }
2403 
2404     /**
2405      * Sets the stroke width and color of the focus rectangle to default value.
2406      *
2407      * @param resource The resources.
2408      */
initialFocusAppearanceLocked(Resources resource)2409     private void initialFocusAppearanceLocked(Resources resource) {
2410         try {
2411             mFocusStrokeWidth = resource.getDimensionPixelSize(
2412                     R.dimen.accessibility_focus_highlight_stroke_width);
2413             mFocusColor = resource.getColor(R.color.accessibility_focus_highlight_color);
2414         } catch (Resources.NotFoundException re) {
2415             // Sets the stroke width and color to default value by hardcoded for making
2416             // the Talkback can work normally.
2417             mFocusStrokeWidth = (int) (4 * resource.getDisplayMetrics().density);
2418             mFocusColor = 0xbf39b500;
2419             Log.e(LOG_TAG, "Error while initialing the focus appearance data then setting to"
2420                     + " default value by hardcoded", re);
2421         }
2422     }
2423 
2424     /**
2425      * Determines if the accessibility button within the system navigation area is supported.
2426      *
2427      * @return {@code true} if the accessibility button is supported on this device,
2428      * {@code false} otherwise
2429      */
isAccessibilityButtonSupported()2430     public static boolean isAccessibilityButtonSupported() {
2431         final Resources res = Resources.getSystem();
2432         return res.getBoolean(com.android.internal.R.bool.config_showNavigationBar);
2433     }
2434 
2435     private final class MyCallback implements Handler.Callback {
2436         public static final int MSG_SET_STATE = 1;
2437 
2438         @Override
handleMessage(Message message)2439         public boolean handleMessage(Message message) {
2440             switch (message.what) {
2441                 case MSG_SET_STATE: {
2442                     // See comment at mClient
2443                     final int state = message.arg1;
2444                     synchronized (mLock) {
2445                         setStateLocked(state);
2446                     }
2447                 } break;
2448             }
2449             return true;
2450         }
2451     }
2452 
2453     /**
2454      * Retrieves the window's transformation matrix and magnification spec.
2455      *
2456      * <p>
2457      * Used by callers outside of the AccessibilityManagerService process which need
2458      * this information, like {@link android.view.accessibility.DirectAccessibilityConnection}.
2459      * </p>
2460      *
2461      * @return The transformation spec
2462      * @hide
2463      */
getWindowTransformationSpec( int windowId)2464     public IAccessibilityManager.WindowTransformationSpec getWindowTransformationSpec(
2465             int windowId) {
2466         final IAccessibilityManager service;
2467         synchronized (mLock) {
2468             service = getServiceLocked();
2469             if (service == null) {
2470                 return null;
2471             }
2472         }
2473         try {
2474             return service.getWindowTransformationSpec(windowId);
2475         } catch (RemoteException re) {
2476             throw re.rethrowFromSystemServer();
2477         }
2478     }
2479 
2480     /**
2481      * Attaches a {@link android.view.SurfaceControl} containing an accessibility overlay to the
2482      * specified display.
2483      *
2484      * @hide
2485      */
2486     @RequiresPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW)
attachAccessibilityOverlayToDisplay( int displayId, @NonNull SurfaceControl surfaceControl)2487     public void attachAccessibilityOverlayToDisplay(
2488             int displayId, @NonNull SurfaceControl surfaceControl) {
2489         final IAccessibilityManager service;
2490         synchronized (mLock) {
2491             service = getServiceLocked();
2492             if (service == null) {
2493                 return;
2494             }
2495         }
2496         try {
2497             service.attachAccessibilityOverlayToDisplay(
2498                     displayId, surfaceControl);
2499         } catch (RemoteException re) {
2500             throw re.rethrowFromSystemServer();
2501         }
2502     }
2503 
2504     /**
2505      * Notifies that the current a11y tiles in QuickSettings Panel has been changed
2506      *
2507      * @param userId            The userId of the user attempts to change the qs panel.
2508      * @param tileComponentNames A list of Accessibility feature's TileServices' component names
2509      *                           and the a11y platform tiles' component names
2510      * @hide
2511      */
2512     @RequiresPermission(Manifest.permission.STATUS_BAR_SERVICE)
notifyQuickSettingsTilesChanged( @serIdInt int userId, List<ComponentName> tileComponentNames)2513     public void notifyQuickSettingsTilesChanged(
2514             @UserIdInt int userId, List<ComponentName> tileComponentNames) {
2515         final IAccessibilityManager service;
2516         synchronized (mLock) {
2517             service = getServiceLocked();
2518             if (service == null) {
2519                 return;
2520             }
2521         }
2522         try {
2523             service.notifyQuickSettingsTilesChanged(userId, tileComponentNames);
2524         } catch (RemoteException re) {
2525             throw re.rethrowFromSystemServer();
2526         }
2527     }
2528 }
2529