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