• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
26 import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
27 import static android.view.accessibility.AccessibilityManager.ShortcutType;
28 
29 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
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.os.Binder;
39 import android.os.RemoteCallbackList;
40 import android.provider.Settings;
41 import android.text.TextUtils;
42 import android.util.ArraySet;
43 import android.util.Slog;
44 import android.view.accessibility.AccessibilityManager;
45 import android.view.accessibility.IAccessibilityManagerClient;
46 
47 import com.android.internal.accessibility.AccessibilityShortcutController;
48 
49 import java.io.FileDescriptor;
50 import java.io.PrintWriter;
51 import java.util.ArrayList;
52 import java.util.Collection;
53 import java.util.HashMap;
54 import java.util.HashSet;
55 import java.util.Iterator;
56 import java.util.List;
57 import java.util.Map;
58 import java.util.Set;
59 
60 /**
61  * Class that hold states and settings per user and share between
62  * {@link AccessibilityManagerService} and {@link AccessibilityServiceConnection}.
63  */
64 class AccessibilityUserState {
65     private static final String LOG_TAG = AccessibilityUserState.class.getSimpleName();
66 
67     final int mUserId;
68 
69     // Non-transient state.
70 
71     final RemoteCallbackList<IAccessibilityManagerClient> mUserClients = new RemoteCallbackList<>();
72 
73     // Transient state.
74 
75     final ArrayList<AccessibilityServiceConnection> mBoundServices = new ArrayList<>();
76 
77     final Map<ComponentName, AccessibilityServiceConnection> mComponentNameToServiceMap =
78             new HashMap<>();
79 
80     final List<AccessibilityServiceInfo> mInstalledServices = new ArrayList<>();
81 
82     final List<AccessibilityShortcutInfo> mInstalledShortcuts = new ArrayList<>();
83 
84     final Set<ComponentName> mBindingServices = new HashSet<>();
85 
86     final Set<ComponentName> mCrashedServices = new HashSet<>();
87 
88     final Set<ComponentName> mEnabledServices = new HashSet<>();
89 
90     final Set<ComponentName> mTouchExplorationGrantedServices = new HashSet<>();
91 
92     final ArraySet<String> mAccessibilityShortcutKeyTargets = new ArraySet<>();
93 
94     final ArraySet<String> mAccessibilityButtonTargets = new ArraySet<>();
95 
96     private final ServiceInfoChangeListener mServiceInfoChangeListener;
97 
98     private ComponentName mServiceChangingSoftKeyboardMode;
99 
100     private String mTargetAssignedToAccessibilityButton;
101 
102     private boolean mBindInstantServiceAllowed;
103     private boolean mIsAutoclickEnabled;
104     private boolean mIsDisplayMagnificationEnabled;
105     private boolean mIsFilterKeyEventsEnabled;
106     private boolean mIsPerformGesturesEnabled;
107     private boolean mAccessibilityFocusOnlyInActiveWindow;
108     private boolean mIsTextHighContrastEnabled;
109     private boolean mIsTouchExplorationEnabled;
110     private boolean mServiceHandlesDoubleTap;
111     private boolean mRequestMultiFingerGestures;
112     private boolean mRequestTwoFingerPassthrough;
113     private int mUserInteractiveUiTimeout;
114     private int mUserNonInteractiveUiTimeout;
115     private int mNonInteractiveUiTimeout = 0;
116     private int mInteractiveUiTimeout = 0;
117     private int mLastSentClientState = -1;
118 
119     private Context mContext;
120 
121     @SoftKeyboardShowMode
122     private int mSoftKeyboardShowMode = SHOW_MODE_AUTO;
123 
124     interface ServiceInfoChangeListener {
onServiceInfoChangedLocked(AccessibilityUserState userState)125         void onServiceInfoChangedLocked(AccessibilityUserState userState);
126     }
127 
AccessibilityUserState(int userId, @NonNull Context context, @NonNull ServiceInfoChangeListener serviceInfoChangeListener)128     AccessibilityUserState(int userId, @NonNull Context context,
129             @NonNull ServiceInfoChangeListener serviceInfoChangeListener) {
130         mUserId = userId;
131         mContext = context;
132         mServiceInfoChangeListener = serviceInfoChangeListener;
133     }
134 
isHandlingAccessibilityEventsLocked()135     boolean isHandlingAccessibilityEventsLocked() {
136         return !mBoundServices.isEmpty() || !mBindingServices.isEmpty();
137     }
138 
onSwitchToAnotherUserLocked()139     void onSwitchToAnotherUserLocked() {
140         // Unbind all services.
141         unbindAllServicesLocked();
142 
143         // Clear service management state.
144         mBoundServices.clear();
145         mBindingServices.clear();
146         mCrashedServices.clear();
147 
148         // Clear event management state.
149         mLastSentClientState = -1;
150 
151         // clear UI timeout
152         mNonInteractiveUiTimeout = 0;
153         mInteractiveUiTimeout = 0;
154 
155         // Clear state persisted in settings.
156         mEnabledServices.clear();
157         mTouchExplorationGrantedServices.clear();
158         mAccessibilityShortcutKeyTargets.clear();
159         mAccessibilityButtonTargets.clear();
160         mTargetAssignedToAccessibilityButton = null;
161         mIsTouchExplorationEnabled = false;
162         mServiceHandlesDoubleTap = false;
163         mRequestMultiFingerGestures = false;
164         mRequestTwoFingerPassthrough = false;
165         mIsDisplayMagnificationEnabled = false;
166         mIsAutoclickEnabled = false;
167         mUserNonInteractiveUiTimeout = 0;
168         mUserInteractiveUiTimeout = 0;
169     }
170 
addServiceLocked(AccessibilityServiceConnection serviceConnection)171     void addServiceLocked(AccessibilityServiceConnection serviceConnection) {
172         if (!mBoundServices.contains(serviceConnection)) {
173             serviceConnection.onAdded();
174             mBoundServices.add(serviceConnection);
175             mComponentNameToServiceMap.put(serviceConnection.getComponentName(), serviceConnection);
176             mServiceInfoChangeListener.onServiceInfoChangedLocked(this);
177         }
178     }
179 
180     /**
181      * Removes a service.
182      * There are three states to a service here: off, bound, and binding.
183      * This stops tracking the service as bound.
184      *
185      * @param serviceConnection The service.
186      */
removeServiceLocked(AccessibilityServiceConnection serviceConnection)187     void removeServiceLocked(AccessibilityServiceConnection serviceConnection) {
188         mBoundServices.remove(serviceConnection);
189         serviceConnection.onRemoved();
190         if ((mServiceChangingSoftKeyboardMode != null)
191                 && (mServiceChangingSoftKeyboardMode.equals(
192                 serviceConnection.getServiceInfo().getComponentName()))) {
193             setSoftKeyboardModeLocked(SHOW_MODE_AUTO, null);
194         }
195         // It may be possible to bind a service twice, which confuses the map. Rebuild the map
196         // to make sure we can still reach a service
197         mComponentNameToServiceMap.clear();
198         for (int i = 0; i < mBoundServices.size(); i++) {
199             AccessibilityServiceConnection boundClient = mBoundServices.get(i);
200             mComponentNameToServiceMap.put(boundClient.getComponentName(), boundClient);
201         }
202         mServiceInfoChangeListener.onServiceInfoChangedLocked(this);
203     }
204 
205     /**
206      * Make sure a services disconnected but still 'on' state is reflected in AccessibilityUserState
207      * There are four states to a service here: off, bound, and binding, and crashed.
208      * This drops a service from a bound state, to the crashed state.
209      * The crashed state describes the situation where a service used to be bound, but no longer is
210      * despite still being enabled.
211      *
212      * @param serviceConnection The service.
213      */
serviceDisconnectedLocked(AccessibilityServiceConnection serviceConnection)214     void serviceDisconnectedLocked(AccessibilityServiceConnection serviceConnection) {
215         removeServiceLocked(serviceConnection);
216         mCrashedServices.add(serviceConnection.getComponentName());
217     }
218 
219     /**
220      * Set the soft keyboard mode. This mode is a bit odd, as it spans multiple settings.
221      * The ACCESSIBILITY_SOFT_KEYBOARD_MODE setting can be checked by the rest of the system
222      * to see if it should suppress showing the IME. The SHOW_IME_WITH_HARD_KEYBOARD setting
223      * setting can be changed by the user, and prevents the system from suppressing the soft
224      * keyboard when the hard keyboard is connected. The hard keyboard setting needs to defer
225      * to the user's preference, if they have supplied one.
226      *
227      * @param newMode The new mode
228      * @param requester The service requesting the change, so we can undo it when the
229      *                  service stops. Set to null if something other than a service is forcing
230      *                  the change.
231      *
232      * @return Whether or not the soft keyboard mode equals the new mode after the call
233      */
setSoftKeyboardModeLocked(@oftKeyboardShowMode int newMode, @Nullable ComponentName requester)234     boolean setSoftKeyboardModeLocked(@SoftKeyboardShowMode int newMode,
235             @Nullable ComponentName requester) {
236         if ((newMode != SHOW_MODE_AUTO)
237                 && (newMode != SHOW_MODE_HIDDEN)
238                 && (newMode != SHOW_MODE_IGNORE_HARD_KEYBOARD)) {
239             Slog.w(LOG_TAG, "Invalid soft keyboard mode");
240             return false;
241         }
242         if (mSoftKeyboardShowMode == newMode) {
243             return true;
244         }
245 
246         if (newMode == SHOW_MODE_IGNORE_HARD_KEYBOARD) {
247             if (hasUserOverriddenHardKeyboardSetting()) {
248                 // The user has specified a default for this setting
249                 return false;
250             }
251             // Save the original value. But don't do this if the value in settings is already
252             // the new mode. That happens when we start up after a reboot, and we don't want
253             // to overwrite the value we had from when we first started controlling the setting.
254             if (getSoftKeyboardValueFromSettings() != SHOW_MODE_IGNORE_HARD_KEYBOARD) {
255                 setOriginalHardKeyboardValue(getSecureIntForUser(
256                         Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0, mUserId) != 0);
257             }
258             putSecureIntForUser(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 1, mUserId);
259         } else if (mSoftKeyboardShowMode == SHOW_MODE_IGNORE_HARD_KEYBOARD) {
260             putSecureIntForUser(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD,
261                     getOriginalHardKeyboardValue() ? 1 : 0, mUserId);
262         }
263 
264         saveSoftKeyboardValueToSettings(newMode);
265         mSoftKeyboardShowMode = newMode;
266         mServiceChangingSoftKeyboardMode = requester;
267         for (int i = mBoundServices.size() - 1; i >= 0; i--) {
268             final AccessibilityServiceConnection service = mBoundServices.get(i);
269             service.notifySoftKeyboardShowModeChangedLocked(mSoftKeyboardShowMode);
270         }
271         return true;
272     }
273 
274     @SoftKeyboardShowMode
getSoftKeyboardShowModeLocked()275     int getSoftKeyboardShowModeLocked() {
276         return mSoftKeyboardShowMode;
277     }
278 
279     /**
280      * If the settings are inconsistent with the internal state, make the internal state
281      * match the settings.
282      */
reconcileSoftKeyboardModeWithSettingsLocked()283     void reconcileSoftKeyboardModeWithSettingsLocked() {
284         final boolean showWithHardKeyboardSettings =
285                 getSecureIntForUser(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0, mUserId) != 0;
286         if (mSoftKeyboardShowMode == SHOW_MODE_IGNORE_HARD_KEYBOARD) {
287             if (!showWithHardKeyboardSettings) {
288                 // The user has overridden the setting. Respect that and prevent further changes
289                 // to this behavior.
290                 setSoftKeyboardModeLocked(SHOW_MODE_AUTO, null);
291                 setUserOverridesHardKeyboardSetting();
292             }
293         }
294 
295         // If the setting and the internal state are out of sync, set both to default
296         if (getSoftKeyboardValueFromSettings() != mSoftKeyboardShowMode) {
297             Slog.e(LOG_TAG, "Show IME setting inconsistent with internal state. Overwriting");
298             setSoftKeyboardModeLocked(SHOW_MODE_AUTO, null);
299             putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
300                     SHOW_MODE_AUTO, mUserId);
301         }
302     }
303 
getBindInstantServiceAllowedLocked()304     boolean getBindInstantServiceAllowedLocked() {
305         return mBindInstantServiceAllowed;
306     }
307 
308     /* Need to have a permission check on callee */
setBindInstantServiceAllowedLocked(boolean allowed)309     void setBindInstantServiceAllowedLocked(boolean allowed) {
310         mBindInstantServiceAllowed = allowed;
311     }
312 
313     /**
314      * Returns binding service list.
315      */
getBindingServicesLocked()316     Set<ComponentName> getBindingServicesLocked() {
317         return mBindingServices;
318     }
319 
320     /**
321      * Returns crashed service list.
322      */
getCrashedServicesLocked()323     Set<ComponentName> getCrashedServicesLocked() {
324         return mCrashedServices;
325     }
326 
327     /**
328      * Returns enabled service list.
329      */
getEnabledServicesLocked()330     Set<ComponentName> getEnabledServicesLocked() {
331         return mEnabledServices;
332     }
333 
334     /**
335      * Remove service from crashed service list if users disable it.
336      */
updateCrashedServicesIfNeededLocked()337     void updateCrashedServicesIfNeededLocked() {
338         for (int i = 0, count = mInstalledServices.size(); i < count; i++) {
339             final AccessibilityServiceInfo installedService = mInstalledServices.get(i);
340             final ComponentName componentName = ComponentName.unflattenFromString(
341                     installedService.getId());
342 
343             if (mCrashedServices.contains(componentName)
344                     && !mEnabledServices.contains(componentName)) {
345                 // Remove it from mCrashedServices since users toggle the switch bar to retry.
346                 mCrashedServices.remove(componentName);
347             }
348         }
349     }
350 
getBoundServicesLocked()351     List<AccessibilityServiceConnection> getBoundServicesLocked() {
352         return mBoundServices;
353     }
354 
getClientStateLocked(boolean isUiAutomationRunning)355     int getClientStateLocked(boolean isUiAutomationRunning) {
356         int clientState = 0;
357         final boolean a11yEnabled = isUiAutomationRunning
358                 || isHandlingAccessibilityEventsLocked();
359         if (a11yEnabled) {
360             clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
361         }
362         // Touch exploration relies on enabled accessibility.
363         if (a11yEnabled && mIsTouchExplorationEnabled) {
364             clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
365             clientState |= AccessibilityManager.STATE_FLAG_DISPATCH_DOUBLE_TAP;
366             clientState |= AccessibilityManager.STATE_FLAG_REQUEST_MULTI_FINGER_GESTURES;
367         }
368         if (mIsTextHighContrastEnabled) {
369             clientState |= AccessibilityManager.STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED;
370         }
371         return clientState;
372     }
373 
setUserOverridesHardKeyboardSetting()374     private void setUserOverridesHardKeyboardSetting() {
375         final int softKeyboardSetting = getSecureIntForUser(
376                 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId);
377         putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
378                 softKeyboardSetting | SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN,
379                 mUserId);
380     }
381 
hasUserOverriddenHardKeyboardSetting()382     private boolean hasUserOverriddenHardKeyboardSetting() {
383         final int softKeyboardSetting = getSecureIntForUser(
384                 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId);
385         return (softKeyboardSetting & SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN)
386                 != 0;
387     }
388 
setOriginalHardKeyboardValue(boolean originalHardKeyboardValue)389     private void setOriginalHardKeyboardValue(boolean originalHardKeyboardValue) {
390         final int oldSoftKeyboardSetting = getSecureIntForUser(
391                 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId);
392         final int newSoftKeyboardSetting = oldSoftKeyboardSetting
393                 & (~SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE)
394                 | ((originalHardKeyboardValue) ? SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE : 0);
395         putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
396                 newSoftKeyboardSetting, mUserId);
397     }
398 
saveSoftKeyboardValueToSettings(int softKeyboardShowMode)399     private void saveSoftKeyboardValueToSettings(int softKeyboardShowMode) {
400         final int oldSoftKeyboardSetting = getSecureIntForUser(
401                 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId);
402         final int newSoftKeyboardSetting = oldSoftKeyboardSetting & (~SHOW_MODE_MASK)
403                 | softKeyboardShowMode;
404         putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
405                 newSoftKeyboardSetting, mUserId);
406     }
407 
getSoftKeyboardValueFromSettings()408     private int getSoftKeyboardValueFromSettings() {
409         return getSecureIntForUser(
410                 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId)
411                 & SHOW_MODE_MASK;
412     }
413 
getOriginalHardKeyboardValue()414     private boolean getOriginalHardKeyboardValue() {
415         return (getSecureIntForUser(
416                 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId)
417                 & SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE) != 0;
418     }
419 
unbindAllServicesLocked()420     private void unbindAllServicesLocked() {
421         final List<AccessibilityServiceConnection> services = mBoundServices;
422         for (int count = services.size(); count > 0; count--) {
423             // When the service is unbound, it disappears from the list, so there's no need to
424             // keep track of the index
425             services.get(0).unbindLocked();
426         }
427     }
428 
getSecureIntForUser(String key, int def, int userId)429     private int getSecureIntForUser(String key, int def, int userId) {
430         return Settings.Secure.getIntForUser(mContext.getContentResolver(), key, def, userId);
431     }
432 
putSecureIntForUser(String key, int value, int userId)433     private void putSecureIntForUser(String key, int value, int userId) {
434         final long identity = Binder.clearCallingIdentity();
435         try {
436             Settings.Secure.putIntForUser(mContext.getContentResolver(), key, value, userId);
437         } finally {
438             Binder.restoreCallingIdentity(identity);
439         }
440     }
441 
dump(FileDescriptor fd, PrintWriter pw, String[] args)442     void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
443         pw.append("User state[");
444         pw.println();
445         pw.append("     attributes:{id=").append(String.valueOf(mUserId));
446         pw.append(", touchExplorationEnabled=").append(String.valueOf(mIsTouchExplorationEnabled));
447         pw.append(", serviceHandlesDoubleTap=")
448                 .append(String.valueOf(mServiceHandlesDoubleTap));
449         pw.append(", requestMultiFingerGestures=")
450                 .append(String.valueOf(mRequestMultiFingerGestures));
451         pw.append(", requestTwoFingerPassthrough=")
452                 .append(String.valueOf(mRequestTwoFingerPassthrough));
453         pw.append(", displayMagnificationEnabled=").append(String.valueOf(
454                 mIsDisplayMagnificationEnabled));
455         pw.append(", autoclickEnabled=").append(String.valueOf(mIsAutoclickEnabled));
456         pw.append(", nonInteractiveUiTimeout=").append(String.valueOf(mNonInteractiveUiTimeout));
457         pw.append(", interactiveUiTimeout=").append(String.valueOf(mInteractiveUiTimeout));
458         pw.append(", installedServiceCount=").append(String.valueOf(mInstalledServices.size()));
459         pw.append("}");
460         pw.println();
461         pw.append("     shortcut key:{");
462         int size = mAccessibilityShortcutKeyTargets.size();
463         for (int i = 0; i < size; i++) {
464             final String componentId = mAccessibilityShortcutKeyTargets.valueAt(i);
465             pw.append(componentId);
466             if (i + 1 < size) {
467                 pw.append(", ");
468             }
469         }
470         pw.println("}");
471         pw.append("     button:{");
472         size = mAccessibilityButtonTargets.size();
473         for (int i = 0; i < size; i++) {
474             final String componentId = mAccessibilityButtonTargets.valueAt(i);
475             pw.append(componentId);
476             if (i + 1 < size) {
477                 pw.append(", ");
478             }
479         }
480         pw.println("}");
481         pw.append("     button target:{").append(mTargetAssignedToAccessibilityButton);
482         pw.println("}");
483         pw.append("     Bound services:{");
484         final int serviceCount = mBoundServices.size();
485         for (int j = 0; j < serviceCount; j++) {
486             if (j > 0) {
487                 pw.append(", ");
488                 pw.println();
489                 pw.append("                     ");
490             }
491             AccessibilityServiceConnection service = mBoundServices.get(j);
492             service.dump(fd, pw, args);
493         }
494         pw.println("}");
495         pw.append("     Enabled services:{");
496         Iterator<ComponentName> it = mEnabledServices.iterator();
497         if (it.hasNext()) {
498             ComponentName componentName = it.next();
499             pw.append(componentName.toShortString());
500             while (it.hasNext()) {
501                 componentName = it.next();
502                 pw.append(", ");
503                 pw.append(componentName.toShortString());
504             }
505         }
506         pw.println("}");
507         pw.append("     Binding services:{");
508         it = mBindingServices.iterator();
509         if (it.hasNext()) {
510             ComponentName componentName = it.next();
511             pw.append(componentName.toShortString());
512             while (it.hasNext()) {
513                 componentName = it.next();
514                 pw.append(", ");
515                 pw.append(componentName.toShortString());
516             }
517         }
518         pw.println("}");
519         pw.append("     Crashed services:{");
520         it = mCrashedServices.iterator();
521         if (it.hasNext()) {
522             ComponentName componentName = it.next();
523             pw.append(componentName.toShortString());
524             while (it.hasNext()) {
525                 componentName = it.next();
526                 pw.append(", ");
527                 pw.append(componentName.toShortString());
528             }
529         }
530         pw.println("}]");
531     }
532 
isAutoclickEnabledLocked()533     public boolean isAutoclickEnabledLocked() {
534         return mIsAutoclickEnabled;
535     }
536 
setAutoclickEnabledLocked(boolean enabled)537     public void setAutoclickEnabledLocked(boolean enabled) {
538         mIsAutoclickEnabled = enabled;
539     }
540 
isDisplayMagnificationEnabledLocked()541     public boolean isDisplayMagnificationEnabledLocked() {
542         return mIsDisplayMagnificationEnabled;
543     }
544 
setDisplayMagnificationEnabledLocked(boolean enabled)545     public void setDisplayMagnificationEnabledLocked(boolean enabled) {
546         mIsDisplayMagnificationEnabled = enabled;
547     }
548 
isFilterKeyEventsEnabledLocked()549     public boolean isFilterKeyEventsEnabledLocked() {
550         return mIsFilterKeyEventsEnabled;
551     }
552 
setFilterKeyEventsEnabledLocked(boolean enabled)553     public void setFilterKeyEventsEnabledLocked(boolean enabled) {
554         mIsFilterKeyEventsEnabled = enabled;
555     }
556 
getInteractiveUiTimeoutLocked()557     public int getInteractiveUiTimeoutLocked() {
558         return mInteractiveUiTimeout;
559     }
560 
setInteractiveUiTimeoutLocked(int timeout)561     public void setInteractiveUiTimeoutLocked(int timeout) {
562         mInteractiveUiTimeout = timeout;
563     }
564 
getLastSentClientStateLocked()565     public int getLastSentClientStateLocked() {
566         return mLastSentClientState;
567     }
568 
setLastSentClientStateLocked(int state)569     public void setLastSentClientStateLocked(int state) {
570         mLastSentClientState = state;
571     }
572 
573     /**
574      * Returns true if navibar magnification or shortcut key magnification is enabled.
575      */
isShortcutMagnificationEnabledLocked()576     public boolean isShortcutMagnificationEnabledLocked() {
577         return mAccessibilityShortcutKeyTargets.contains(MAGNIFICATION_CONTROLLER_NAME)
578                 || mAccessibilityButtonTargets.contains(MAGNIFICATION_CONTROLLER_NAME);
579     }
580 
581     /**
582      * Disable both shortcuts' magnification function.
583      */
disableShortcutMagnificationLocked()584     public void disableShortcutMagnificationLocked() {
585         mAccessibilityShortcutKeyTargets.remove(MAGNIFICATION_CONTROLLER_NAME);
586         mAccessibilityButtonTargets.remove(MAGNIFICATION_CONTROLLER_NAME);
587     }
588 
589     /**
590      * Returns a set which contains the flattened component names and the system class names
591      * assigned to the given shortcut.
592      *
593      * @param shortcutType The shortcut type.
594      * @return The array set of the strings
595      */
getShortcutTargetsLocked(@hortcutType int shortcutType)596     public ArraySet<String> getShortcutTargetsLocked(@ShortcutType int shortcutType) {
597         if (shortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
598             return mAccessibilityShortcutKeyTargets;
599         } else if (shortcutType == ACCESSIBILITY_BUTTON) {
600             return mAccessibilityButtonTargets;
601         }
602         return null;
603     }
604 
605     /**
606      * Whether or not the given shortcut target is installed in device.
607      *
608      * @param name The shortcut target name
609      * @return true if the shortcut target is installed.
610      */
isShortcutTargetInstalledLocked(String name)611     public boolean isShortcutTargetInstalledLocked(String name) {
612         if (TextUtils.isEmpty(name)) {
613             return false;
614         }
615         if (MAGNIFICATION_CONTROLLER_NAME.equals(name)) {
616             return true;
617         }
618 
619         final ComponentName componentName = ComponentName.unflattenFromString(name);
620         if (componentName == null) {
621             return false;
622         }
623         if (AccessibilityShortcutController.getFrameworkShortcutFeaturesMap()
624                 .containsKey(componentName)) {
625             return true;
626         }
627         if (getInstalledServiceInfoLocked(componentName) != null) {
628             return true;
629         }
630         for (int i = 0; i < mInstalledShortcuts.size(); i++) {
631             if (mInstalledShortcuts.get(i).getComponentName().equals(componentName)) {
632                 return true;
633             }
634         }
635         return false;
636     }
637 
638     /**
639      * Removes given shortcut target in the list.
640      *
641      * @param shortcutType The shortcut type.
642      * @param target The component name of the shortcut target.
643      * @return true if the shortcut target is removed.
644      */
removeShortcutTargetLocked(@hortcutType int shortcutType, ComponentName target)645     public boolean removeShortcutTargetLocked(@ShortcutType int shortcutType,
646             ComponentName target) {
647         return getShortcutTargetsLocked(shortcutType).removeIf(name -> {
648             ComponentName componentName;
649             if (name == null
650                     || (componentName = ComponentName.unflattenFromString(name)) == null) {
651                 return false;
652             }
653             return componentName.equals(target);
654         });
655     }
656 
657     /**
658      * Returns installed accessibility service info by the given service component name.
659      */
getInstalledServiceInfoLocked(ComponentName componentName)660     public AccessibilityServiceInfo getInstalledServiceInfoLocked(ComponentName componentName) {
661         for (int i = 0; i < mInstalledServices.size(); i++) {
662             final AccessibilityServiceInfo serviceInfo = mInstalledServices.get(i);
663             if (serviceInfo.getComponentName().equals(componentName)) {
664                 return serviceInfo;
665             }
666         }
667         return null;
668     }
669 
670     /**
671      * Returns accessibility service connection by the given service component name.
672      */
getServiceConnectionLocked(ComponentName componentName)673     public AccessibilityServiceConnection getServiceConnectionLocked(ComponentName componentName) {
674         return mComponentNameToServiceMap.get(componentName);
675     }
676 
getNonInteractiveUiTimeoutLocked()677     public int getNonInteractiveUiTimeoutLocked() {
678         return mNonInteractiveUiTimeout;
679     }
680 
setNonInteractiveUiTimeoutLocked(int timeout)681     public void setNonInteractiveUiTimeoutLocked(int timeout) {
682         mNonInteractiveUiTimeout = timeout;
683     }
684 
isPerformGesturesEnabledLocked()685     public boolean isPerformGesturesEnabledLocked() {
686         return mIsPerformGesturesEnabled;
687     }
688 
setPerformGesturesEnabledLocked(boolean enabled)689     public void setPerformGesturesEnabledLocked(boolean enabled) {
690         mIsPerformGesturesEnabled = enabled;
691     }
692 
isAccessibilityFocusOnlyInActiveWindow()693     public boolean isAccessibilityFocusOnlyInActiveWindow() {
694         return mAccessibilityFocusOnlyInActiveWindow;
695     }
696 
setAccessibilityFocusOnlyInActiveWindow(boolean enabled)697     public void setAccessibilityFocusOnlyInActiveWindow(boolean enabled) {
698         mAccessibilityFocusOnlyInActiveWindow = enabled;
699     }
getServiceChangingSoftKeyboardModeLocked()700     public ComponentName getServiceChangingSoftKeyboardModeLocked() {
701         return mServiceChangingSoftKeyboardMode;
702     }
703 
setServiceChangingSoftKeyboardModeLocked( ComponentName serviceChangingSoftKeyboardMode)704     public void setServiceChangingSoftKeyboardModeLocked(
705             ComponentName serviceChangingSoftKeyboardMode) {
706         mServiceChangingSoftKeyboardMode = serviceChangingSoftKeyboardMode;
707     }
708 
isTextHighContrastEnabledLocked()709     public boolean isTextHighContrastEnabledLocked() {
710         return mIsTextHighContrastEnabled;
711     }
712 
setTextHighContrastEnabledLocked(boolean enabled)713     public void setTextHighContrastEnabledLocked(boolean enabled) {
714         mIsTextHighContrastEnabled = enabled;
715     }
716 
isTouchExplorationEnabledLocked()717     public boolean isTouchExplorationEnabledLocked() {
718         return mIsTouchExplorationEnabled;
719     }
720 
setTouchExplorationEnabledLocked(boolean enabled)721     public void setTouchExplorationEnabledLocked(boolean enabled) {
722         mIsTouchExplorationEnabled = enabled;
723     }
724 
isServiceHandlesDoubleTapEnabledLocked()725     public boolean isServiceHandlesDoubleTapEnabledLocked() {
726         return mServiceHandlesDoubleTap;
727     }
728 
setServiceHandlesDoubleTapLocked(boolean enabled)729     public void setServiceHandlesDoubleTapLocked(boolean enabled) {
730         mServiceHandlesDoubleTap = enabled;
731     }
732 
isMultiFingerGesturesEnabledLocked()733     public boolean isMultiFingerGesturesEnabledLocked() {
734         return mRequestMultiFingerGestures;
735     }
736 
setMultiFingerGesturesLocked(boolean enabled)737     public void setMultiFingerGesturesLocked(boolean enabled) {
738         mRequestMultiFingerGestures = enabled;
739     }
isTwoFingerPassthroughEnabledLocked()740     public boolean isTwoFingerPassthroughEnabledLocked() {
741         return mRequestTwoFingerPassthrough;
742     }
743 
setTwoFingerPassthroughLocked(boolean enabled)744     public void setTwoFingerPassthroughLocked(boolean enabled) {
745         mRequestTwoFingerPassthrough = enabled;
746     }
747 
748 
getUserInteractiveUiTimeoutLocked()749     public int getUserInteractiveUiTimeoutLocked() {
750         return mUserInteractiveUiTimeout;
751     }
752 
setUserInteractiveUiTimeoutLocked(int timeout)753     public void setUserInteractiveUiTimeoutLocked(int timeout) {
754         mUserInteractiveUiTimeout = timeout;
755     }
756 
getUserNonInteractiveUiTimeoutLocked()757     public int getUserNonInteractiveUiTimeoutLocked() {
758         return mUserNonInteractiveUiTimeout;
759     }
760 
setUserNonInteractiveUiTimeoutLocked(int timeout)761     public void setUserNonInteractiveUiTimeoutLocked(int timeout) {
762         mUserNonInteractiveUiTimeout = timeout;
763     }
764 
765     /**
766      * Gets a shortcut target which is assigned to the accessibility button by the chooser
767      * activity.
768      *
769      * @return The flattened component name or the system class name of the shortcut target.
770      */
getTargetAssignedToAccessibilityButton()771     public String getTargetAssignedToAccessibilityButton() {
772         return mTargetAssignedToAccessibilityButton;
773     }
774 
775     /**
776      * Sets a shortcut target which is assigned to the accessibility button by the chooser
777      * activity.
778      *
779      * @param target The flattened component name or the system class name of the shortcut target.
780      */
setTargetAssignedToAccessibilityButton(String target)781     public void setTargetAssignedToAccessibilityButton(String target) {
782         mTargetAssignedToAccessibilityButton = target;
783     }
784 
785     /**
786      * Whether or not the given target name is contained in the shortcut collection. Since the
787      * component name string format could be short or long, this function un-flatten the component
788      * name from the string in {@code shortcutTargets} and compared with the given target name.
789      *
790      * @param shortcutTargets The shortcut type.
791      * @param targetName The target name.
792      * @return {@code true} if the target is in the shortcut collection.
793      */
doesShortcutTargetsStringContain(Collection<String> shortcutTargets, String targetName)794     public static boolean doesShortcutTargetsStringContain(Collection<String> shortcutTargets,
795             String targetName) {
796         if (shortcutTargets == null || targetName == null) {
797             return false;
798         }
799         // Some system features, such as magnification, don't have component name. Using string
800         // compare first.
801         if (shortcutTargets.contains(targetName)) {
802             return true;
803         }
804         final ComponentName targetComponentName = ComponentName.unflattenFromString(targetName);
805         if (targetComponentName == null) {
806             return false;
807         }
808         for (String stringName : shortcutTargets) {
809             if (!TextUtils.isEmpty(stringName)
810                     && targetComponentName.equals(ComponentName.unflattenFromString(stringName))) {
811                 return true;
812             }
813         }
814         return false;
815     }
816 }
817