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