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