1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.accessibility;
18 
19 import static android.accessibilityservice.AccessibilityService.SHOW_MODE_AUTO;
20 import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE;
21 import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN;
22 import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN;
23 import static android.accessibilityservice.AccessibilityService.SHOW_MODE_IGNORE_HARD_KEYBOARD;
24 import static android.accessibilityservice.AccessibilityService.SHOW_MODE_MASK;
25 import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
26 import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
27 
28 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
29 import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
30 
31 import android.accessibilityservice.AccessibilityService.SoftKeyboardShowMode;
32 import android.accessibilityservice.AccessibilityServiceInfo;
33 import android.accessibilityservice.AccessibilityShortcutInfo;
34 import android.annotation.NonNull;
35 import android.annotation.Nullable;
36 import android.content.ComponentName;
37 import android.content.Context;
38 import android.content.pm.PackageManager;
39 import android.content.pm.ResolveInfo;
40 import android.os.Binder;
41 import android.os.RemoteCallbackList;
42 import android.provider.Settings;
43 import android.text.TextUtils;
44 import android.util.ArrayMap;
45 import android.util.ArraySet;
46 import android.util.Slog;
47 import android.util.SparseArray;
48 import android.util.SparseIntArray;
49 import android.view.accessibility.AccessibilityManager;
50 import android.view.accessibility.IAccessibilityManagerClient;
51 
52 import com.android.internal.R;
53 import com.android.internal.accessibility.AccessibilityShortcutController;
54 
55 import java.io.FileDescriptor;
56 import java.io.PrintWriter;
57 import java.util.ArrayList;
58 import java.util.Arrays;
59 import java.util.Collection;
60 import java.util.HashMap;
61 import java.util.HashSet;
62 import java.util.Iterator;
63 import java.util.List;
64 import java.util.Map;
65 import java.util.Set;
66 import java.util.function.Function;
67 import java.util.stream.Collectors;
68 
69 /**
70  * Class that hold states and settings per user and share between
71  * {@link AccessibilityManagerService} and {@link AccessibilityServiceConnection}.
72  */
73 class AccessibilityUserState {
74     private static final String LOG_TAG = AccessibilityUserState.class.getSimpleName();
75 
76     final int mUserId;
77 
78     // Non-transient state.
79 
80     final RemoteCallbackList<IAccessibilityManagerClient> mUserClients = new RemoteCallbackList<>();
81 
82     // Transient state.
83 
84     final ArrayList<AccessibilityServiceConnection> mBoundServices = new ArrayList<>();
85 
86     final Map<ComponentName, AccessibilityServiceConnection> mComponentNameToServiceMap =
87             new HashMap<>();
88 
89     final List<AccessibilityServiceInfo> mInstalledServices = new ArrayList<>();
90 
91     final List<AccessibilityShortcutInfo> mInstalledShortcuts = new ArrayList<>();
92 
93     final Set<ComponentName> mBindingServices = new HashSet<>();
94 
95     final Set<ComponentName> mCrashedServices = new HashSet<>();
96 
97     final Set<ComponentName> mEnabledServices = new HashSet<>();
98 
99     final Set<ComponentName> mTouchExplorationGrantedServices = new HashSet<>();
100 
101     final ArraySet<String> mAccessibilityShortcutKeyTargets = new ArraySet<>();
102 
103     final ArraySet<String> mAccessibilityButtonTargets = new ArraySet<>();
104     private final ArraySet<String> mAccessibilityQsTargets = new ArraySet<>();
105 
106     /**
107      * The QuickSettings tiles in the QS Panel. This can be different from
108      * {@link #mAccessibilityQsTargets} in that {@link #mA11yTilesInQsPanel} stores the
109      * TileService's or the a11y framework tile component names (e.g.
110      * {@link AccessibilityShortcutController#COLOR_INVERSION_TILE_COMPONENT_NAME}) instead of the
111      * A11y Feature's component names.
112      * <p/>
113      * In addition, {@link #mA11yTilesInQsPanel} stores what's on the QS Panel, whereas
114      * {@link #mAccessibilityQsTargets} stores the targets that configured qs as their shortcut and
115      * also grant full device control permission.
116      */
117     private final ArraySet<ComponentName> mA11yTilesInQsPanel = new ArraySet<>();
118 
119     private final ServiceInfoChangeListener mServiceInfoChangeListener;
120 
121     private ComponentName mServiceChangingSoftKeyboardMode;
122 
123     private String mTargetAssignedToAccessibilityButton;
124 
125     private boolean mBindInstantServiceAllowed;
126     private boolean mIsAudioDescriptionByDefaultRequested;
127     private boolean mIsAutoclickEnabled;
128     private boolean mIsMagnificationSingleFingerTripleTapEnabled;
129     private boolean mMagnificationTwoFingerTripleTapEnabled;
130     private boolean mIsFilterKeyEventsEnabled;
131     private boolean mIsPerformGesturesEnabled;
132     private boolean mAccessibilityFocusOnlyInActiveWindow;
133     private boolean mIsTextHighContrastEnabled;
134     private boolean mIsTouchExplorationEnabled;
135     private boolean mServiceHandlesDoubleTap;
136     private boolean mRequestMultiFingerGestures;
137     private boolean mRequestTwoFingerPassthrough;
138     private boolean mSendMotionEventsEnabled;
139     private SparseArray<Boolean> mServiceDetectsGestures = new SparseArray<>(0);
140     private int mUserInteractiveUiTimeout;
141     private int mUserNonInteractiveUiTimeout;
142     private int mNonInteractiveUiTimeout = 0;
143     private int mInteractiveUiTimeout = 0;
144     private int mLastSentClientState = -1;
145 
146     /** {@code true} if the device config supports window magnification. */
147     private final boolean mSupportWindowMagnification;
148     // The magnification modes on displays.
149     private final SparseIntArray mMagnificationModes = new SparseIntArray();
150     // The magnification capabilities used to know magnification mode could be switched.
151     private int mMagnificationCapabilities = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
152     // Whether the following typing focus feature for magnification is enabled.
153     private boolean mMagnificationFollowTypingEnabled = true;
154     // Whether the always on magnification feature is enabled.
155     private boolean mAlwaysOnMagnificationEnabled = false;
156 
157     /** The stroke width of the focus rectangle in pixels */
158     private int mFocusStrokeWidth;
159     /** The color of the focus rectangle */
160     private int mFocusColor;
161     // The default value of the focus stroke width.
162     private final int mFocusStrokeWidthDefaultValue;
163     // The default value of the focus color.
164     private final int mFocusColorDefaultValue;
165     private final Map<ComponentName, ComponentName> mA11yServiceToTileService = new ArrayMap<>();
166     private final Map<ComponentName, ComponentName> mA11yActivityToTileService = new ArrayMap<>();
167 
168     private Context mContext;
169 
170     @SoftKeyboardShowMode
171     private int mSoftKeyboardShowMode = SHOW_MODE_AUTO;
172 
isValidMagnificationModeLocked(int displayId)173     boolean isValidMagnificationModeLocked(int displayId) {
174         final int mode = getMagnificationModeLocked(displayId);
175         if (!mSupportWindowMagnification
176                 && mode == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
177             return false;
178         }
179         return (mMagnificationCapabilities & mode) != 0;
180     }
181 
182     interface ServiceInfoChangeListener {
onServiceInfoChangedLocked(AccessibilityUserState userState)183         void onServiceInfoChangedLocked(AccessibilityUserState userState);
184     }
185 
AccessibilityUserState(int userId, @NonNull Context context, @NonNull ServiceInfoChangeListener serviceInfoChangeListener)186     AccessibilityUserState(int userId, @NonNull Context context,
187             @NonNull ServiceInfoChangeListener serviceInfoChangeListener) {
188         mUserId = userId;
189         mContext = context;
190         mServiceInfoChangeListener = serviceInfoChangeListener;
191         mFocusStrokeWidthDefaultValue = mContext.getResources().getDimensionPixelSize(
192                 R.dimen.accessibility_focus_highlight_stroke_width);
193         mFocusColorDefaultValue = mContext.getResources().getColor(
194                 R.color.accessibility_focus_highlight_color);
195         mFocusStrokeWidth = mFocusStrokeWidthDefaultValue;
196         mFocusColor = mFocusColorDefaultValue;
197         mSupportWindowMagnification = mContext.getResources().getBoolean(
198                 R.bool.config_magnification_area) && mContext.getPackageManager().hasSystemFeature(
199                 PackageManager.FEATURE_WINDOW_MAGNIFICATION);
200     }
201 
isHandlingAccessibilityEventsLocked()202     boolean isHandlingAccessibilityEventsLocked() {
203         return !mBoundServices.isEmpty() || !mBindingServices.isEmpty();
204     }
205 
onSwitchToAnotherUserLocked()206     void onSwitchToAnotherUserLocked() {
207         // Unbind all services.
208         unbindAllServicesLocked();
209 
210         // Clear service management state.
211         mBoundServices.clear();
212         mBindingServices.clear();
213         mCrashedServices.clear();
214 
215         // Clear event management state.
216         mLastSentClientState = -1;
217 
218         // clear UI timeout
219         mNonInteractiveUiTimeout = 0;
220         mInteractiveUiTimeout = 0;
221 
222         // Clear state persisted in settings.
223         mEnabledServices.clear();
224         mTouchExplorationGrantedServices.clear();
225         mAccessibilityShortcutKeyTargets.clear();
226         mAccessibilityButtonTargets.clear();
227         mTargetAssignedToAccessibilityButton = null;
228         mIsTouchExplorationEnabled = false;
229         mServiceHandlesDoubleTap = false;
230         mRequestMultiFingerGestures = false;
231         mRequestTwoFingerPassthrough = false;
232         mSendMotionEventsEnabled = false;
233         mIsMagnificationSingleFingerTripleTapEnabled = false;
234         mMagnificationTwoFingerTripleTapEnabled = false;
235         mIsAutoclickEnabled = false;
236         mUserNonInteractiveUiTimeout = 0;
237         mUserInteractiveUiTimeout = 0;
238         mMagnificationModes.clear();
239         mFocusStrokeWidth = mFocusStrokeWidthDefaultValue;
240         mFocusColor = mFocusColorDefaultValue;
241         mMagnificationFollowTypingEnabled = true;
242         mAlwaysOnMagnificationEnabled = false;
243     }
244 
addServiceLocked(AccessibilityServiceConnection serviceConnection)245     void addServiceLocked(AccessibilityServiceConnection serviceConnection) {
246         if (!mBoundServices.contains(serviceConnection)) {
247             mBoundServices.add(serviceConnection);
248             mComponentNameToServiceMap.put(serviceConnection.getComponentName(), serviceConnection);
249             mServiceInfoChangeListener.onServiceInfoChangedLocked(this);
250         }
251     }
252 
253     /**
254      * Removes a service.
255      * There are three states to a service here: off, bound, and binding.
256      * This stops tracking the service as bound.
257      *
258      * @param serviceConnection The service.
259      */
removeServiceLocked(AccessibilityServiceConnection serviceConnection)260     void removeServiceLocked(AccessibilityServiceConnection serviceConnection) {
261         mBoundServices.remove(serviceConnection);
262         serviceConnection.onRemoved();
263         if ((mServiceChangingSoftKeyboardMode != null)
264                 && (mServiceChangingSoftKeyboardMode.equals(
265                 serviceConnection.getServiceInfo().getComponentName()))) {
266             setSoftKeyboardModeLocked(SHOW_MODE_AUTO, null);
267         }
268         // It may be possible to bind a service twice, which confuses the map. Rebuild the map
269         // to make sure we can still reach a service
270         mComponentNameToServiceMap.clear();
271         for (int i = 0; i < mBoundServices.size(); i++) {
272             AccessibilityServiceConnection boundClient = mBoundServices.get(i);
273             mComponentNameToServiceMap.put(boundClient.getComponentName(), boundClient);
274         }
275         mServiceInfoChangeListener.onServiceInfoChangedLocked(this);
276     }
277 
278     /**
279      * Make sure a services disconnected but still 'on' state is reflected in AccessibilityUserState
280      * There are four states to a service here: off, bound, and binding, and crashed.
281      * This drops a service from a bound state, to the crashed state.
282      * The crashed state describes the situation where a service used to be bound, but no longer is
283      * despite still being enabled.
284      *
285      * @param serviceConnection The service.
286      */
serviceDisconnectedLocked(AccessibilityServiceConnection serviceConnection)287     void serviceDisconnectedLocked(AccessibilityServiceConnection serviceConnection) {
288         removeServiceLocked(serviceConnection);
289         mCrashedServices.add(serviceConnection.getComponentName());
290     }
291 
292     /**
293      * Set the soft keyboard mode. This mode is a bit odd, as it spans multiple settings.
294      * The ACCESSIBILITY_SOFT_KEYBOARD_MODE setting can be checked by the rest of the system
295      * to see if it should suppress showing the IME. The SHOW_IME_WITH_HARD_KEYBOARD setting
296      * setting can be changed by the user, and prevents the system from suppressing the soft
297      * keyboard when the hard keyboard is connected. The hard keyboard setting needs to defer
298      * to the user's preference, if they have supplied one.
299      *
300      * @param newMode The new mode
301      * @param requester The service requesting the change, so we can undo it when the
302      *                  service stops. Set to null if something other than a service is forcing
303      *                  the change.
304      *
305      * @return Whether or not the soft keyboard mode equals the new mode after the call
306      */
setSoftKeyboardModeLocked(@oftKeyboardShowMode int newMode, @Nullable ComponentName requester)307     boolean setSoftKeyboardModeLocked(@SoftKeyboardShowMode int newMode,
308             @Nullable ComponentName requester) {
309         if ((newMode != SHOW_MODE_AUTO)
310                 && (newMode != SHOW_MODE_HIDDEN)
311                 && (newMode != SHOW_MODE_IGNORE_HARD_KEYBOARD)) {
312             Slog.w(LOG_TAG, "Invalid soft keyboard mode");
313             return false;
314         }
315         if (mSoftKeyboardShowMode == newMode) {
316             return true;
317         }
318 
319         if (newMode == SHOW_MODE_IGNORE_HARD_KEYBOARD) {
320             if (hasUserOverriddenHardKeyboardSetting()) {
321                 // The user has specified a default for this setting
322                 return false;
323             }
324             // Save the original value. But don't do this if the value in settings is already
325             // the new mode. That happens when we start up after a reboot, and we don't want
326             // to overwrite the value we had from when we first started controlling the setting.
327             if (getSoftKeyboardValueFromSettings() != SHOW_MODE_IGNORE_HARD_KEYBOARD) {
328                 setOriginalHardKeyboardValue(getSecureIntForUser(
329                         Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0, mUserId) != 0);
330             }
331             putSecureIntForUser(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 1, mUserId);
332         } else if (mSoftKeyboardShowMode == SHOW_MODE_IGNORE_HARD_KEYBOARD) {
333             putSecureIntForUser(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD,
334                     getOriginalHardKeyboardValue() ? 1 : 0, mUserId);
335         }
336 
337         saveSoftKeyboardValueToSettings(newMode);
338         mSoftKeyboardShowMode = newMode;
339         mServiceChangingSoftKeyboardMode = requester;
340         for (int i = mBoundServices.size() - 1; i >= 0; i--) {
341             final AccessibilityServiceConnection service = mBoundServices.get(i);
342             service.notifySoftKeyboardShowModeChangedLocked(mSoftKeyboardShowMode);
343         }
344         return true;
345     }
346 
347     @SoftKeyboardShowMode
getSoftKeyboardShowModeLocked()348     int getSoftKeyboardShowModeLocked() {
349         return mSoftKeyboardShowMode;
350     }
351 
352     /**
353      * If the settings are inconsistent with the internal state, make the internal state
354      * match the settings.
355      */
reconcileSoftKeyboardModeWithSettingsLocked()356     void reconcileSoftKeyboardModeWithSettingsLocked() {
357         final boolean showWithHardKeyboardSettings =
358                 getSecureIntForUser(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0, mUserId) != 0;
359         if (mSoftKeyboardShowMode == SHOW_MODE_IGNORE_HARD_KEYBOARD) {
360             if (!showWithHardKeyboardSettings) {
361                 // The user has overridden the setting. Respect that and prevent further changes
362                 // to this behavior.
363                 setSoftKeyboardModeLocked(SHOW_MODE_AUTO, null);
364                 setUserOverridesHardKeyboardSetting();
365             }
366         }
367 
368         // If the setting and the internal state are out of sync, set both to default
369         if (getSoftKeyboardValueFromSettings() != mSoftKeyboardShowMode) {
370             Slog.e(LOG_TAG, "Show IME setting inconsistent with internal state. Overwriting");
371             setSoftKeyboardModeLocked(SHOW_MODE_AUTO, null);
372             putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
373                     SHOW_MODE_AUTO, mUserId);
374         }
375     }
376 
getBindInstantServiceAllowedLocked()377     boolean getBindInstantServiceAllowedLocked() {
378         return mBindInstantServiceAllowed;
379     }
380 
381     /* Need to have a permission check on callee */
setBindInstantServiceAllowedLocked(boolean allowed)382     void setBindInstantServiceAllowedLocked(boolean allowed) {
383         mBindInstantServiceAllowed = allowed;
384     }
385 
386     /**
387      * Returns binding service list.
388      */
getBindingServicesLocked()389     Set<ComponentName> getBindingServicesLocked() {
390         return mBindingServices;
391     }
392 
393     /**
394      * Returns crashed service list.
395      */
getCrashedServicesLocked()396     Set<ComponentName> getCrashedServicesLocked() {
397         return mCrashedServices;
398     }
399 
400     /**
401      * Returns enabled service list.
402      */
getEnabledServicesLocked()403     Set<ComponentName> getEnabledServicesLocked() {
404         return mEnabledServices;
405     }
406 
407     /**
408      * Remove the service from the crashed and binding service lists if the user disabled it.
409      */
removeDisabledServicesFromTemporaryStatesLocked()410     void removeDisabledServicesFromTemporaryStatesLocked() {
411         for (int i = 0, count = mInstalledServices.size(); i < count; i++) {
412             final AccessibilityServiceInfo installedService = mInstalledServices.get(i);
413             final ComponentName componentName = ComponentName.unflattenFromString(
414                     installedService.getId());
415 
416             if (!mEnabledServices.contains(componentName)) {
417                 // Remove from mCrashedServices, since users may toggle the on/off switch to retry.
418                 mCrashedServices.remove(componentName);
419                 // Remove from mBindingServices, since services can get stuck in the binding state
420                 // if binding starts but never finishes. If the service later attempts to finish
421                 // binding but it is not in the enabled list then it will exit before initializing;
422                 // see AccessibilityServiceConnection#initializeService().
423                 mBindingServices.remove(componentName);
424             }
425         }
426     }
427 
getBoundServicesLocked()428     List<AccessibilityServiceConnection> getBoundServicesLocked() {
429         return mBoundServices;
430     }
431 
getClientStateLocked(boolean uiAutomationCanIntrospect, int traceClientState)432     int getClientStateLocked(boolean uiAutomationCanIntrospect,
433             int traceClientState) {
434         int clientState = 0;
435         final boolean a11yEnabled = uiAutomationCanIntrospect
436                 || isHandlingAccessibilityEventsLocked();
437         if (a11yEnabled) {
438             clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
439         }
440         // Touch exploration relies on enabled accessibility.
441         if (a11yEnabled && mIsTouchExplorationEnabled) {
442             clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
443             clientState |= AccessibilityManager.STATE_FLAG_DISPATCH_DOUBLE_TAP;
444             clientState |= AccessibilityManager.STATE_FLAG_REQUEST_MULTI_FINGER_GESTURES;
445         }
446         if (mIsTextHighContrastEnabled) {
447             clientState |= AccessibilityManager.STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED;
448         }
449         if (mIsAudioDescriptionByDefaultRequested) {
450             clientState |=
451                     AccessibilityManager.STATE_FLAG_AUDIO_DESCRIPTION_BY_DEFAULT_ENABLED;
452         }
453 
454         clientState |= traceClientState;
455 
456         return clientState;
457     }
458 
setUserOverridesHardKeyboardSetting()459     private void setUserOverridesHardKeyboardSetting() {
460         final int softKeyboardSetting = getSecureIntForUser(
461                 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId);
462         putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
463                 softKeyboardSetting | SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN,
464                 mUserId);
465     }
466 
hasUserOverriddenHardKeyboardSetting()467     private boolean hasUserOverriddenHardKeyboardSetting() {
468         final int softKeyboardSetting = getSecureIntForUser(
469                 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId);
470         return (softKeyboardSetting & SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN)
471                 != 0;
472     }
473 
setOriginalHardKeyboardValue(boolean originalHardKeyboardValue)474     private void setOriginalHardKeyboardValue(boolean originalHardKeyboardValue) {
475         final int oldSoftKeyboardSetting = getSecureIntForUser(
476                 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId);
477         final int newSoftKeyboardSetting = oldSoftKeyboardSetting
478                 & (~SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE)
479                 | ((originalHardKeyboardValue) ? SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE : 0);
480         putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
481                 newSoftKeyboardSetting, mUserId);
482     }
483 
saveSoftKeyboardValueToSettings(int softKeyboardShowMode)484     private void saveSoftKeyboardValueToSettings(int softKeyboardShowMode) {
485         final int oldSoftKeyboardSetting = getSecureIntForUser(
486                 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId);
487         final int newSoftKeyboardSetting = oldSoftKeyboardSetting & (~SHOW_MODE_MASK)
488                 | softKeyboardShowMode;
489         putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
490                 newSoftKeyboardSetting, mUserId);
491     }
492 
getSoftKeyboardValueFromSettings()493     private int getSoftKeyboardValueFromSettings() {
494         return getSecureIntForUser(
495                 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId)
496                 & SHOW_MODE_MASK;
497     }
498 
getOriginalHardKeyboardValue()499     private boolean getOriginalHardKeyboardValue() {
500         return (getSecureIntForUser(
501                 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId)
502                 & SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE) != 0;
503     }
504 
unbindAllServicesLocked()505     private void unbindAllServicesLocked() {
506         final List<AccessibilityServiceConnection> services = mBoundServices;
507         for (int count = services.size(); count > 0; count--) {
508             // When the service is unbound, it disappears from the list, so there's no need to
509             // keep track of the index
510             services.get(0).unbindLocked();
511         }
512     }
513 
getSecureIntForUser(String key, int def, int userId)514     private int getSecureIntForUser(String key, int def, int userId) {
515         return Settings.Secure.getIntForUser(mContext.getContentResolver(), key, def, userId);
516     }
517 
putSecureIntForUser(String key, int value, int userId)518     private void putSecureIntForUser(String key, int value, int userId) {
519         final long identity = Binder.clearCallingIdentity();
520         try {
521             Settings.Secure.putIntForUser(mContext.getContentResolver(), key, value, userId);
522         } finally {
523             Binder.restoreCallingIdentity(identity);
524         }
525     }
526 
dump(FileDescriptor fd, PrintWriter pw, String[] args)527     void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
528         pw.append("User state[");
529         pw.println();
530         pw.append("     attributes:{id=").append(String.valueOf(mUserId));
531         pw.append(", touchExplorationEnabled=").append(String.valueOf(mIsTouchExplorationEnabled));
532         pw.append(", serviceHandlesDoubleTap=")
533                 .append(String.valueOf(mServiceHandlesDoubleTap));
534         pw.append(", requestMultiFingerGestures=")
535                 .append(String.valueOf(mRequestMultiFingerGestures));
536         pw.append(", requestTwoFingerPassthrough=")
537                 .append(String.valueOf(mRequestTwoFingerPassthrough));
538         pw.append(", sendMotionEventsEnabled").append(String.valueOf(mSendMotionEventsEnabled));
539         pw.append(", displayMagnificationEnabled=").append(String.valueOf(
540                 mIsMagnificationSingleFingerTripleTapEnabled));
541         pw.append(", autoclickEnabled=").append(String.valueOf(mIsAutoclickEnabled));
542         pw.append(", nonInteractiveUiTimeout=").append(String.valueOf(mNonInteractiveUiTimeout));
543         pw.append(", interactiveUiTimeout=").append(String.valueOf(mInteractiveUiTimeout));
544         pw.append(", installedServiceCount=").append(String.valueOf(mInstalledServices.size()));
545         pw.append(", magnificationModes=").append(String.valueOf(mMagnificationModes));
546         pw.append(", magnificationCapabilities=")
547                 .append(String.valueOf(mMagnificationCapabilities));
548         pw.append(", audioDescriptionByDefaultEnabled=")
549                 .append(String.valueOf(mIsAudioDescriptionByDefaultRequested));
550         pw.append(", magnificationFollowTypingEnabled=")
551                 .append(String.valueOf(mMagnificationFollowTypingEnabled));
552         pw.append(", alwaysOnMagnificationEnabled=")
553                 .append(String.valueOf(mAlwaysOnMagnificationEnabled));
554         pw.append("}");
555         pw.println();
556         pw.append("     shortcut key:{");
557         int size = mAccessibilityShortcutKeyTargets.size();
558         for (int i = 0; i < size; i++) {
559             final String componentId = mAccessibilityShortcutKeyTargets.valueAt(i);
560             pw.append(componentId);
561             if (i + 1 < size) {
562                 pw.append(", ");
563             }
564         }
565         pw.println("}");
566         pw.append("     button:{");
567         size = mAccessibilityButtonTargets.size();
568         for (int i = 0; i < size; i++) {
569             final String componentId = mAccessibilityButtonTargets.valueAt(i);
570             pw.append(componentId);
571             if (i + 1 < size) {
572                 pw.append(", ");
573             }
574         }
575         pw.println("}");
576         pw.append("     button target:{").append(mTargetAssignedToAccessibilityButton);
577         pw.println("}");
578         pw.append("     qs shortcut targets:").append(mAccessibilityQsTargets.toString());
579         pw.println();
580         pw.append("     a11y tiles in QS panel:").append(mA11yTilesInQsPanel.toString());
581         pw.println();
582         pw.append("     Bound services:{");
583         final int serviceCount = mBoundServices.size();
584         for (int j = 0; j < serviceCount; j++) {
585             if (j > 0) {
586                 pw.append(", ");
587                 pw.println();
588                 pw.append("                     ");
589             }
590             AccessibilityServiceConnection service = mBoundServices.get(j);
591             service.dump(fd, pw, args);
592         }
593         pw.println("}");
594         pw.append("     Enabled services:{");
595         Iterator<ComponentName> it = mEnabledServices.iterator();
596         if (it.hasNext()) {
597             ComponentName componentName = it.next();
598             pw.append(componentName.toShortString());
599             while (it.hasNext()) {
600                 componentName = it.next();
601                 pw.append(", ");
602                 pw.append(componentName.toShortString());
603             }
604         }
605         pw.println("}");
606         pw.append("     Binding services:{");
607         it = mBindingServices.iterator();
608         if (it.hasNext()) {
609             ComponentName componentName = it.next();
610             pw.append(componentName.toShortString());
611             while (it.hasNext()) {
612                 componentName = it.next();
613                 pw.append(", ");
614                 pw.append(componentName.toShortString());
615             }
616         }
617         pw.println("}");
618         pw.append("     Crashed services:{");
619         it = mCrashedServices.iterator();
620         if (it.hasNext()) {
621             ComponentName componentName = it.next();
622             pw.append(componentName.toShortString());
623             while (it.hasNext()) {
624                 componentName = it.next();
625                 pw.append(", ");
626                 pw.append(componentName.toShortString());
627             }
628         }
629         pw.println("}");
630         pw.println("     Client list info:{");
631         mUserClients.dump(pw, "          Client list ");
632         pw.println("          Registered clients:{");
633         for (int i = 0; i < mUserClients.getRegisteredCallbackCount(); i++) {
634             AccessibilityManagerService.Client client = (AccessibilityManagerService.Client)
635                     mUserClients.getRegisteredCallbackCookie(i);
636             pw.append(Arrays.toString(client.mPackageNames));
637         }
638         pw.println("}]");
639     }
640 
isAutoclickEnabledLocked()641     public boolean isAutoclickEnabledLocked() {
642         return mIsAutoclickEnabled;
643     }
644 
setAutoclickEnabledLocked(boolean enabled)645     public void setAutoclickEnabledLocked(boolean enabled) {
646         mIsAutoclickEnabled = enabled;
647     }
648 
isMagnificationSingleFingerTripleTapEnabledLocked()649     public boolean isMagnificationSingleFingerTripleTapEnabledLocked() {
650         return mIsMagnificationSingleFingerTripleTapEnabled;
651     }
652 
setMagnificationSingleFingerTripleTapEnabledLocked(boolean enabled)653     public void setMagnificationSingleFingerTripleTapEnabledLocked(boolean enabled) {
654         mIsMagnificationSingleFingerTripleTapEnabled = enabled;
655     }
656 
isMagnificationTwoFingerTripleTapEnabledLocked()657     public boolean isMagnificationTwoFingerTripleTapEnabledLocked() {
658         return mMagnificationTwoFingerTripleTapEnabled;
659     }
660 
setMagnificationTwoFingerTripleTapEnabledLocked(boolean enabled)661     public void setMagnificationTwoFingerTripleTapEnabledLocked(boolean enabled) {
662         mMagnificationTwoFingerTripleTapEnabled = enabled;
663     }
664 
isFilterKeyEventsEnabledLocked()665     public boolean isFilterKeyEventsEnabledLocked() {
666         return mIsFilterKeyEventsEnabled;
667     }
668 
setFilterKeyEventsEnabledLocked(boolean enabled)669     public void setFilterKeyEventsEnabledLocked(boolean enabled) {
670         mIsFilterKeyEventsEnabled = enabled;
671     }
672 
getInteractiveUiTimeoutLocked()673     public int getInteractiveUiTimeoutLocked() {
674         return mInteractiveUiTimeout;
675     }
676 
setInteractiveUiTimeoutLocked(int timeout)677     public void setInteractiveUiTimeoutLocked(int timeout) {
678         mInteractiveUiTimeout = timeout;
679     }
680 
getLastSentClientStateLocked()681     public int getLastSentClientStateLocked() {
682         return mLastSentClientState;
683     }
684 
setLastSentClientStateLocked(int state)685     public void setLastSentClientStateLocked(int state) {
686         mLastSentClientState = state;
687     }
688 
689     /**
690      * Returns true if navibar magnification or shortcut key magnification is enabled.
691      */
isShortcutMagnificationEnabledLocked()692     public boolean isShortcutMagnificationEnabledLocked() {
693         return mAccessibilityShortcutKeyTargets.contains(MAGNIFICATION_CONTROLLER_NAME)
694                 || mAccessibilityButtonTargets.contains(MAGNIFICATION_CONTROLLER_NAME);
695     }
696 
697     /**
698      * Gets the magnification mode for the given display.
699      * @return magnification mode
700      *
701      * @see Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN
702      * @see Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
703      */
getMagnificationModeLocked(int displayId)704     public int getMagnificationModeLocked(int displayId) {
705         int mode = mMagnificationModes.get(displayId, ACCESSIBILITY_MAGNIFICATION_MODE_NONE);
706         if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_NONE) {
707             mode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
708             setMagnificationModeLocked(displayId, mode);
709         }
710         return mode;
711     }
712 
713 
714     /**
715      * Gets the magnification capabilities setting of current user.
716      *
717      * @return magnification capabilities
718      *
719      * @see Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN
720      * @see Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
721      * @see Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_ALL
722      */
getMagnificationCapabilitiesLocked()723     int getMagnificationCapabilitiesLocked() {
724         return mMagnificationCapabilities;
725     }
726 
727     /**
728      * Sets the magnification capabilities from Settings value.
729      *
730      * @see Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN
731      * @see Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
732      * @see Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_ALL
733      */
setMagnificationCapabilitiesLocked(int capabilities)734     public void setMagnificationCapabilitiesLocked(int capabilities) {
735         mMagnificationCapabilities = capabilities;
736     }
737 
setMagnificationFollowTypingEnabled(boolean enabled)738     public void setMagnificationFollowTypingEnabled(boolean enabled) {
739         mMagnificationFollowTypingEnabled = enabled;
740     }
741 
isMagnificationFollowTypingEnabled()742     public boolean isMagnificationFollowTypingEnabled() {
743         return mMagnificationFollowTypingEnabled;
744     }
745 
setAlwaysOnMagnificationEnabled(boolean enabled)746     public void setAlwaysOnMagnificationEnabled(boolean enabled) {
747         mAlwaysOnMagnificationEnabled = enabled;
748     }
749 
isAlwaysOnMagnificationEnabled()750     public boolean isAlwaysOnMagnificationEnabled() {
751         return mAlwaysOnMagnificationEnabled;
752     }
753 
754     /**
755      * Sets the magnification mode to the given display.
756      *
757      * @param displayId The display id.
758      * @param mode The magnification mode.
759      */
setMagnificationModeLocked(int displayId, int mode)760     public void setMagnificationModeLocked(int displayId, int mode) {
761         mMagnificationModes.put(displayId, mode);
762     }
763 
764     /**
765      * Disable both shortcuts' magnification function.
766      */
disableShortcutMagnificationLocked()767     public void disableShortcutMagnificationLocked() {
768         mAccessibilityShortcutKeyTargets.remove(MAGNIFICATION_CONTROLLER_NAME);
769         mAccessibilityButtonTargets.remove(MAGNIFICATION_CONTROLLER_NAME);
770     }
771 
772     /**
773      * Returns a set which contains the flattened component names and the system class names
774      * assigned to the given shortcut.
775      *
776      * @param shortcutType The shortcut type.
777      * @return The array set of the strings
778      */
getShortcutTargetsLocked(@serShortcutType int shortcutType)779     public ArraySet<String> getShortcutTargetsLocked(@UserShortcutType int shortcutType) {
780         if (shortcutType == UserShortcutType.HARDWARE) {
781             return mAccessibilityShortcutKeyTargets;
782         } else if (shortcutType == UserShortcutType.SOFTWARE) {
783             return mAccessibilityButtonTargets;
784         } else if (shortcutType == UserShortcutType.QUICK_SETTINGS) {
785             return getA11yQsTargets();
786         } else if ((shortcutType == UserShortcutType.TRIPLETAP
787                 && isMagnificationSingleFingerTripleTapEnabledLocked()) || (
788                 shortcutType == UserShortcutType.TWOFINGER_DOUBLETAP
789                         && isMagnificationTwoFingerTripleTapEnabledLocked())) {
790             ArraySet<String> targets = new ArraySet<>();
791             targets.add(MAGNIFICATION_CONTROLLER_NAME);
792             return targets;
793         }
794         return new ArraySet<>();
795     }
796 
797     /**
798      * Whether or not the given shortcut target is installed in device.
799      *
800      * @param name The shortcut target name
801      * @return true if the shortcut target is installed.
802      */
isShortcutTargetInstalledLocked(String name)803     public boolean isShortcutTargetInstalledLocked(String name) {
804         if (TextUtils.isEmpty(name)) {
805             return false;
806         }
807         if (MAGNIFICATION_CONTROLLER_NAME.equals(name)) {
808             return true;
809         }
810 
811         final ComponentName componentName = ComponentName.unflattenFromString(name);
812         if (componentName == null) {
813             return false;
814         }
815         if (AccessibilityShortcutController.getFrameworkShortcutFeaturesMap()
816                 .containsKey(componentName)) {
817             return true;
818         }
819         if (getInstalledServiceInfoLocked(componentName) != null) {
820             return true;
821         }
822         for (int i = 0; i < mInstalledShortcuts.size(); i++) {
823             if (mInstalledShortcuts.get(i).getComponentName().equals(componentName)) {
824                 return true;
825             }
826         }
827         return false;
828     }
829 
830     /**
831      * Removes given shortcut target in the list.
832      *
833      * @param shortcutType The shortcut type.
834      * @param target The component name of the shortcut target.
835      * @return true if the shortcut target is removed.
836      */
removeShortcutTargetLocked( @serShortcutType int shortcutType, ComponentName target)837     public boolean removeShortcutTargetLocked(
838             @UserShortcutType int shortcutType, ComponentName target) {
839         if (shortcutType == UserShortcutType.TRIPLETAP
840                 || shortcutType == UserShortcutType.TWOFINGER_DOUBLETAP) {
841             throw new UnsupportedOperationException(
842                     "removeShortcutTargetLocked only support shortcut type: "
843                             + "software and hardware and quick settings for now"
844             );
845         }
846 
847         Set<String> targets = getShortcutTargetsLocked(shortcutType);
848         boolean result = targets.removeIf(name -> {
849             ComponentName componentName;
850             if (name == null
851                     || (componentName = ComponentName.unflattenFromString(name)) == null) {
852                 return false;
853             }
854             return componentName.equals(target);
855         });
856         if (shortcutType == UserShortcutType.QUICK_SETTINGS) {
857             updateA11yQsTargetLocked(targets);
858         }
859 
860         return result;
861     }
862 
863     /**
864      * Returns installed accessibility service info by the given service component name.
865      */
getInstalledServiceInfoLocked(ComponentName componentName)866     public AccessibilityServiceInfo getInstalledServiceInfoLocked(ComponentName componentName) {
867         for (int i = 0; i < mInstalledServices.size(); i++) {
868             final AccessibilityServiceInfo serviceInfo = mInstalledServices.get(i);
869             if (serviceInfo.getComponentName().equals(componentName)) {
870                 return serviceInfo;
871             }
872         }
873         return null;
874     }
875 
876     /**
877      * Returns accessibility service connection by the given service component name.
878      */
getServiceConnectionLocked(ComponentName componentName)879     public AccessibilityServiceConnection getServiceConnectionLocked(ComponentName componentName) {
880         return mComponentNameToServiceMap.get(componentName);
881     }
882 
getNonInteractiveUiTimeoutLocked()883     public int getNonInteractiveUiTimeoutLocked() {
884         return mNonInteractiveUiTimeout;
885     }
886 
setNonInteractiveUiTimeoutLocked(int timeout)887     public void setNonInteractiveUiTimeoutLocked(int timeout) {
888         mNonInteractiveUiTimeout = timeout;
889     }
890 
isPerformGesturesEnabledLocked()891     public boolean isPerformGesturesEnabledLocked() {
892         return mIsPerformGesturesEnabled;
893     }
894 
setPerformGesturesEnabledLocked(boolean enabled)895     public void setPerformGesturesEnabledLocked(boolean enabled) {
896         mIsPerformGesturesEnabled = enabled;
897     }
898 
isAccessibilityFocusOnlyInActiveWindow()899     public boolean isAccessibilityFocusOnlyInActiveWindow() {
900         return mAccessibilityFocusOnlyInActiveWindow;
901     }
902 
setAccessibilityFocusOnlyInActiveWindow(boolean enabled)903     public void setAccessibilityFocusOnlyInActiveWindow(boolean enabled) {
904         mAccessibilityFocusOnlyInActiveWindow = enabled;
905     }
getServiceChangingSoftKeyboardModeLocked()906     public ComponentName getServiceChangingSoftKeyboardModeLocked() {
907         return mServiceChangingSoftKeyboardMode;
908     }
909 
setServiceChangingSoftKeyboardModeLocked( ComponentName serviceChangingSoftKeyboardMode)910     public void setServiceChangingSoftKeyboardModeLocked(
911             ComponentName serviceChangingSoftKeyboardMode) {
912         mServiceChangingSoftKeyboardMode = serviceChangingSoftKeyboardMode;
913     }
914 
isTextHighContrastEnabledLocked()915     public boolean isTextHighContrastEnabledLocked() {
916         return mIsTextHighContrastEnabled;
917     }
918 
setTextHighContrastEnabledLocked(boolean enabled)919     public void setTextHighContrastEnabledLocked(boolean enabled) {
920         mIsTextHighContrastEnabled = enabled;
921     }
922 
isAudioDescriptionByDefaultEnabledLocked()923     public boolean isAudioDescriptionByDefaultEnabledLocked() {
924         return mIsAudioDescriptionByDefaultRequested;
925     }
926 
setAudioDescriptionByDefaultEnabledLocked(boolean enabled)927     public void setAudioDescriptionByDefaultEnabledLocked(boolean enabled) {
928         mIsAudioDescriptionByDefaultRequested = enabled;
929     }
930 
isTouchExplorationEnabledLocked()931     public boolean isTouchExplorationEnabledLocked() {
932         return mIsTouchExplorationEnabled;
933     }
934 
setTouchExplorationEnabledLocked(boolean enabled)935     public void setTouchExplorationEnabledLocked(boolean enabled) {
936         mIsTouchExplorationEnabled = enabled;
937     }
938 
isServiceHandlesDoubleTapEnabledLocked()939     public boolean isServiceHandlesDoubleTapEnabledLocked() {
940         return mServiceHandlesDoubleTap;
941     }
942 
setServiceHandlesDoubleTapLocked(boolean enabled)943     public void setServiceHandlesDoubleTapLocked(boolean enabled) {
944         mServiceHandlesDoubleTap = enabled;
945     }
946 
isMultiFingerGesturesEnabledLocked()947     public boolean isMultiFingerGesturesEnabledLocked() {
948         return mRequestMultiFingerGestures;
949     }
950 
setMultiFingerGesturesLocked(boolean enabled)951     public void setMultiFingerGesturesLocked(boolean enabled) {
952         mRequestMultiFingerGestures = enabled;
953     }
isTwoFingerPassthroughEnabledLocked()954     public boolean isTwoFingerPassthroughEnabledLocked() {
955         return mRequestTwoFingerPassthrough;
956     }
957 
setTwoFingerPassthroughLocked(boolean enabled)958     public void setTwoFingerPassthroughLocked(boolean enabled) {
959         mRequestTwoFingerPassthrough = enabled;
960     }
961 
isSendMotionEventsEnabled()962     public boolean isSendMotionEventsEnabled() {
963         return mSendMotionEventsEnabled;
964     }
965 
setSendMotionEventsEnabled(boolean mode)966     public void setSendMotionEventsEnabled(boolean mode) {
967         mSendMotionEventsEnabled = mode;
968     }
969 
getUserInteractiveUiTimeoutLocked()970     public int getUserInteractiveUiTimeoutLocked() {
971         return mUserInteractiveUiTimeout;
972     }
973 
setUserInteractiveUiTimeoutLocked(int timeout)974     public void setUserInteractiveUiTimeoutLocked(int timeout) {
975         mUserInteractiveUiTimeout = timeout;
976     }
977 
getUserNonInteractiveUiTimeoutLocked()978     public int getUserNonInteractiveUiTimeoutLocked() {
979         return mUserNonInteractiveUiTimeout;
980     }
981 
setUserNonInteractiveUiTimeoutLocked(int timeout)982     public void setUserNonInteractiveUiTimeoutLocked(int timeout) {
983         mUserNonInteractiveUiTimeout = timeout;
984     }
985 
986     /**
987      * Gets a shortcut target which is assigned to the accessibility button by the chooser
988      * activity.
989      *
990      * @return The flattened component name or the system class name of the shortcut target.
991      */
getTargetAssignedToAccessibilityButton()992     public String getTargetAssignedToAccessibilityButton() {
993         return mTargetAssignedToAccessibilityButton;
994     }
995 
996     /**
997      * Sets a shortcut target which is assigned to the accessibility button by the chooser
998      * activity.
999      *
1000      * @param target The flattened component name or the system class name of the shortcut target.
1001      */
setTargetAssignedToAccessibilityButton(String target)1002     public void setTargetAssignedToAccessibilityButton(String target) {
1003         mTargetAssignedToAccessibilityButton = target;
1004     }
1005 
1006     /**
1007      * Whether or not the given target name is contained in the shortcut collection. Since the
1008      * component name string format could be short or long, this function un-flatten the component
1009      * name from the string in {@code shortcutTargets} and compared with the given target name.
1010      *
1011      * @param shortcutTargets The shortcut type.
1012      * @param targetName The target name.
1013      * @return {@code true} if the target is in the shortcut collection.
1014      */
doesShortcutTargetsStringContain(Collection<String> shortcutTargets, String targetName)1015     public static boolean doesShortcutTargetsStringContain(Collection<String> shortcutTargets,
1016             String targetName) {
1017         if (shortcutTargets == null || targetName == null) {
1018             return false;
1019         }
1020         // Some system features, such as magnification, don't have component name. Using string
1021         // compare first.
1022         if (shortcutTargets.contains(targetName)) {
1023             return true;
1024         }
1025         final ComponentName targetComponentName = ComponentName.unflattenFromString(targetName);
1026         if (targetComponentName == null) {
1027             return false;
1028         }
1029         for (String stringName : shortcutTargets) {
1030             if (!TextUtils.isEmpty(stringName)
1031                     && targetComponentName.equals(ComponentName.unflattenFromString(stringName))) {
1032                 return true;
1033             }
1034         }
1035         return false;
1036     }
1037 
1038     /**
1039      * Gets the stroke width of the focus rectangle.
1040      * @return The stroke width.
1041      */
getFocusStrokeWidthLocked()1042     public int getFocusStrokeWidthLocked() {
1043         return mFocusStrokeWidth;
1044     }
1045 
1046     /**
1047      * Gets the color of the focus rectangle.
1048      * @return The color.
1049      */
getFocusColorLocked()1050     public int getFocusColorLocked() {
1051         return mFocusColor;
1052     }
1053 
1054     /**
1055      * Sets the stroke width and color of the focus rectangle.
1056      *
1057      * @param strokeWidth The strokeWidth of the focus rectangle.
1058      * @param color The color of the focus rectangle.
1059      */
setFocusAppearanceLocked(int strokeWidth, int color)1060     public void setFocusAppearanceLocked(int strokeWidth, int color) {
1061         mFocusStrokeWidth = strokeWidth;
1062         mFocusColor = color;
1063     }
1064 
setServiceDetectsGesturesEnabled(int displayId, boolean mode)1065     public void setServiceDetectsGesturesEnabled(int displayId, boolean mode) {
1066         mServiceDetectsGestures.put(displayId, mode);
1067     }
1068 
resetServiceDetectsGestures()1069     public void resetServiceDetectsGestures() {
1070         mServiceDetectsGestures.clear();
1071     }
1072 
isServiceDetectsGesturesEnabled(int displayId)1073     public boolean isServiceDetectsGesturesEnabled(int displayId) {
1074         if (mServiceDetectsGestures.contains(displayId)) {
1075             return mServiceDetectsGestures.get(displayId);
1076         }
1077         return false;
1078     }
1079 
updateTileServiceMapForAccessibilityServiceLocked()1080     public void updateTileServiceMapForAccessibilityServiceLocked() {
1081         mA11yServiceToTileService.clear();
1082         mInstalledServices.forEach(
1083                 a11yServiceInfo -> {
1084                     String tileServiceName = a11yServiceInfo.getTileServiceName();
1085                     if (!TextUtils.isEmpty(tileServiceName)) {
1086                         ResolveInfo resolveInfo = a11yServiceInfo.getResolveInfo();
1087                         ComponentName a11yFeature = new ComponentName(
1088                                 resolveInfo.serviceInfo.packageName,
1089                                 resolveInfo.serviceInfo.name
1090                         );
1091                         ComponentName tileService = new ComponentName(
1092                                 a11yFeature.getPackageName(),
1093                                 tileServiceName
1094                         );
1095                         mA11yServiceToTileService.put(a11yFeature, tileService);
1096                     }
1097                 }
1098         );
1099     }
1100 
updateTileServiceMapForAccessibilityActivityLocked()1101     public void updateTileServiceMapForAccessibilityActivityLocked() {
1102         mA11yActivityToTileService.clear();
1103         mInstalledShortcuts.forEach(
1104                 a11yShortcutInfo -> {
1105                     String tileServiceName = a11yShortcutInfo.getTileServiceName();
1106                     if (!TextUtils.isEmpty(tileServiceName)) {
1107                         ComponentName a11yFeature = a11yShortcutInfo.getComponentName();
1108                         ComponentName tileService = new ComponentName(
1109                                 a11yFeature.getPackageName(),
1110                                 tileServiceName);
1111                         mA11yActivityToTileService.put(a11yFeature, tileService);
1112                     }
1113                 }
1114         );
1115     }
1116 
updateA11yQsTargetLocked(Set<String> targets)1117     public void updateA11yQsTargetLocked(Set<String> targets) {
1118         mAccessibilityQsTargets.clear();
1119         mAccessibilityQsTargets.addAll(targets);
1120     }
1121 
1122     /**
1123      * Returns a copy of the targets which has qs shortcut turned on
1124      */
getA11yQsTargets()1125     public ArraySet<String> getA11yQsTargets() {
1126         return new ArraySet<>(mAccessibilityQsTargets);
1127     }
1128 
updateA11yTilesInQsPanelLocked(Set<ComponentName> componentNames)1129     public void updateA11yTilesInQsPanelLocked(Set<ComponentName> componentNames) {
1130         mA11yTilesInQsPanel.clear();
1131         mA11yTilesInQsPanel.addAll(componentNames);
1132     }
1133 
1134     /**
1135      * Returns a copy of the a11y tiles that are in the QuickSettings panel
1136      */
getA11yQsTilesInQsPanel()1137     public ArraySet<ComponentName> getA11yQsTilesInQsPanel() {
1138         return new ArraySet<>(mA11yTilesInQsPanel);
1139     }
1140 
1141     /**
1142      * Returns a map of AccessibilityService or AccessibilityShortcut to its provided TileService
1143      */
getA11yFeatureToTileService()1144     public Map<ComponentName, ComponentName> getA11yFeatureToTileService() {
1145         Map<ComponentName, ComponentName> featureToTileServiceMap = new ArrayMap<>();
1146         featureToTileServiceMap.putAll(mA11yServiceToTileService);
1147         featureToTileServiceMap.putAll(mA11yActivityToTileService);
1148         return featureToTileServiceMap;
1149     }
1150 
1151     /**
1152      * Returns a map of TileService's componentName to the AccessibilityServiceInfo it ties to.
1153      */
getTileServiceToA11yServiceInfoMapLocked()1154     public Map<ComponentName, AccessibilityServiceInfo> getTileServiceToA11yServiceInfoMapLocked() {
1155         Map<ComponentName, AccessibilityServiceInfo> tileServiceToA11yServiceInfoMap =
1156                 new ArrayMap<>();
1157         Map<ComponentName, AccessibilityServiceInfo> a11yServiceToServiceInfoMap =
1158                 mInstalledServices.stream().collect(
1159                         Collectors.toMap(
1160                                 AccessibilityServiceInfo::getComponentName,
1161                                 Function.identity()));
1162         for (Map.Entry<ComponentName, ComponentName> serviceToTile :
1163                 mA11yServiceToTileService.entrySet()) {
1164             if (a11yServiceToServiceInfoMap.containsKey(serviceToTile.getKey())) {
1165                 tileServiceToA11yServiceInfoMap.put(serviceToTile.getValue(),
1166                         a11yServiceToServiceInfoMap.get(serviceToTile.getKey()));
1167             }
1168         }
1169         return tileServiceToA11yServiceInfoMap;
1170     }
1171 }
1172