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