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