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