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