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