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