blob: bad649ab6b0261030d2ac2f827271333092494fd [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.accessibility;
import static android.accessibilityservice.AccessibilityService.SHOW_MODE_AUTO;
import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE;
import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN;
import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN;
import static android.accessibilityservice.AccessibilityService.SHOW_MODE_IGNORE_HARD_KEYBOARD;
import static android.accessibilityservice.AccessibilityService.SHOW_MODE_MASK;
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
import static android.view.accessibility.AccessibilityManager.ShortcutType;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import android.accessibilityservice.AccessibilityService.SoftKeyboardShowMode;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.AccessibilityShortcutInfo;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.os.Binder;
import android.os.RemoteCallbackList;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Slog;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManagerClient;
import com.android.internal.accessibility.AccessibilityShortcutController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Class that hold states and settings per user and share between
* {@link AccessibilityManagerService} and {@link AccessibilityServiceConnection}.
*/
class AccessibilityUserState {
private static final String LOG_TAG = AccessibilityUserState.class.getSimpleName();
final int mUserId;
// Non-transient state.
final RemoteCallbackList<IAccessibilityManagerClient> mUserClients = new RemoteCallbackList<>();
// Transient state.
final ArrayList<AccessibilityServiceConnection> mBoundServices = new ArrayList<>();
final Map<ComponentName, AccessibilityServiceConnection> mComponentNameToServiceMap =
new HashMap<>();
final List<AccessibilityServiceInfo> mInstalledServices = new ArrayList<>();
final List<AccessibilityShortcutInfo> mInstalledShortcuts = new ArrayList<>();
final Set<ComponentName> mBindingServices = new HashSet<>();
final Set<ComponentName> mCrashedServices = new HashSet<>();
final Set<ComponentName> mEnabledServices = new HashSet<>();
final Set<ComponentName> mTouchExplorationGrantedServices = new HashSet<>();
final ArraySet<String> mAccessibilityShortcutKeyTargets = new ArraySet<>();
final ArraySet<String> mAccessibilityButtonTargets = new ArraySet<>();
private final ServiceInfoChangeListener mServiceInfoChangeListener;
private ComponentName mServiceChangingSoftKeyboardMode;
private String mTargetAssignedToAccessibilityButton;
private boolean mBindInstantServiceAllowed;
private boolean mIsAutoclickEnabled;
private boolean mIsDisplayMagnificationEnabled;
private boolean mIsFilterKeyEventsEnabled;
private boolean mIsPerformGesturesEnabled;
private boolean mIsTextHighContrastEnabled;
private boolean mIsTouchExplorationEnabled;
private boolean mServiceHandlesDoubleTap;
private boolean mRequestMultiFingerGestures;
private int mUserInteractiveUiTimeout;
private int mUserNonInteractiveUiTimeout;
private int mNonInteractiveUiTimeout = 0;
private int mInteractiveUiTimeout = 0;
private int mLastSentClientState = -1;
private Context mContext;
@SoftKeyboardShowMode
private int mSoftKeyboardShowMode = SHOW_MODE_AUTO;
interface ServiceInfoChangeListener {
void onServiceInfoChangedLocked(AccessibilityUserState userState);
}
AccessibilityUserState(int userId, @NonNull Context context,
@NonNull ServiceInfoChangeListener serviceInfoChangeListener) {
mUserId = userId;
mContext = context;
mServiceInfoChangeListener = serviceInfoChangeListener;
}
boolean isHandlingAccessibilityEventsLocked() {
return !mBoundServices.isEmpty() || !mBindingServices.isEmpty();
}
void onSwitchToAnotherUserLocked() {
// Unbind all services.
unbindAllServicesLocked();
// Clear service management state.
mBoundServices.clear();
mBindingServices.clear();
mCrashedServices.clear();
// Clear event management state.
mLastSentClientState = -1;
// clear UI timeout
mNonInteractiveUiTimeout = 0;
mInteractiveUiTimeout = 0;
// Clear state persisted in settings.
mEnabledServices.clear();
mTouchExplorationGrantedServices.clear();
mAccessibilityShortcutKeyTargets.clear();
mAccessibilityButtonTargets.clear();
mTargetAssignedToAccessibilityButton = null;
mIsTouchExplorationEnabled = false;
mServiceHandlesDoubleTap = false;
mRequestMultiFingerGestures = false;
mIsDisplayMagnificationEnabled = false;
mIsAutoclickEnabled = false;
mUserNonInteractiveUiTimeout = 0;
mUserInteractiveUiTimeout = 0;
}
void addServiceLocked(AccessibilityServiceConnection serviceConnection) {
if (!mBoundServices.contains(serviceConnection)) {
serviceConnection.onAdded();
mBoundServices.add(serviceConnection);
mComponentNameToServiceMap.put(serviceConnection.getComponentName(), serviceConnection);
mServiceInfoChangeListener.onServiceInfoChangedLocked(this);
}
}
/**
* Removes a service.
* There are three states to a service here: off, bound, and binding.
* This stops tracking the service as bound.
*
* @param serviceConnection The service.
*/
void removeServiceLocked(AccessibilityServiceConnection serviceConnection) {
mBoundServices.remove(serviceConnection);
serviceConnection.onRemoved();
if ((mServiceChangingSoftKeyboardMode != null)
&& (mServiceChangingSoftKeyboardMode.equals(
serviceConnection.getServiceInfo().getComponentName()))) {
setSoftKeyboardModeLocked(SHOW_MODE_AUTO, null);
}
// It may be possible to bind a service twice, which confuses the map. Rebuild the map
// to make sure we can still reach a service
mComponentNameToServiceMap.clear();
for (int i = 0; i < mBoundServices.size(); i++) {
AccessibilityServiceConnection boundClient = mBoundServices.get(i);
mComponentNameToServiceMap.put(boundClient.getComponentName(), boundClient);
}
mServiceInfoChangeListener.onServiceInfoChangedLocked(this);
}
/**
* Make sure a services disconnected but still 'on' state is reflected in AccessibilityUserState
* There are four states to a service here: off, bound, and binding, and crashed.
* This drops a service from a bound state, to the crashed state.
* The crashed state describes the situation where a service used to be bound, but no longer is
* despite still being enabled.
*
* @param serviceConnection The service.
*/
void serviceDisconnectedLocked(AccessibilityServiceConnection serviceConnection) {
removeServiceLocked(serviceConnection);
mCrashedServices.add(serviceConnection.getComponentName());
}
/**
* Set the soft keyboard mode. This mode is a bit odd, as it spans multiple settings.
* The ACCESSIBILITY_SOFT_KEYBOARD_MODE setting can be checked by the rest of the system
* to see if it should suppress showing the IME. The SHOW_IME_WITH_HARD_KEYBOARD setting
* setting can be changed by the user, and prevents the system from suppressing the soft
* keyboard when the hard keyboard is connected. The hard keyboard setting needs to defer
* to the user's preference, if they have supplied one.
*
* @param newMode The new mode
* @param requester The service requesting the change, so we can undo it when the
* service stops. Set to null if something other than a service is forcing
* the change.
*
* @return Whether or not the soft keyboard mode equals the new mode after the call
*/
boolean setSoftKeyboardModeLocked(@SoftKeyboardShowMode int newMode,
@Nullable ComponentName requester) {
if ((newMode != SHOW_MODE_AUTO)
&& (newMode != SHOW_MODE_HIDDEN)
&& (newMode != SHOW_MODE_IGNORE_HARD_KEYBOARD)) {
Slog.w(LOG_TAG, "Invalid soft keyboard mode");
return false;
}
if (mSoftKeyboardShowMode == newMode) {
return true;
}
if (newMode == SHOW_MODE_IGNORE_HARD_KEYBOARD) {
if (hasUserOverriddenHardKeyboardSetting()) {
// The user has specified a default for this setting
return false;
}
// Save the original value. But don't do this if the value in settings is already
// the new mode. That happens when we start up after a reboot, and we don't want
// to overwrite the value we had from when we first started controlling the setting.
if (getSoftKeyboardValueFromSettings() != SHOW_MODE_IGNORE_HARD_KEYBOARD) {
setOriginalHardKeyboardValue(getSecureIntForUser(
Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0, mUserId) != 0);
}
putSecureIntForUser(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 1, mUserId);
} else if (mSoftKeyboardShowMode == SHOW_MODE_IGNORE_HARD_KEYBOARD) {
putSecureIntForUser(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD,
getOriginalHardKeyboardValue() ? 1 : 0, mUserId);
}
saveSoftKeyboardValueToSettings(newMode);
mSoftKeyboardShowMode = newMode;
mServiceChangingSoftKeyboardMode = requester;
for (int i = mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = mBoundServices.get(i);
service.notifySoftKeyboardShowModeChangedLocked(mSoftKeyboardShowMode);
}
return true;
}
@SoftKeyboardShowMode
int getSoftKeyboardShowModeLocked() {
return mSoftKeyboardShowMode;
}
/**
* If the settings are inconsistent with the internal state, make the internal state
* match the settings.
*/
void reconcileSoftKeyboardModeWithSettingsLocked() {
final boolean showWithHardKeyboardSettings =
getSecureIntForUser(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0, mUserId) != 0;
if (mSoftKeyboardShowMode == SHOW_MODE_IGNORE_HARD_KEYBOARD) {
if (!showWithHardKeyboardSettings) {
// The user has overridden the setting. Respect that and prevent further changes
// to this behavior.
setSoftKeyboardModeLocked(SHOW_MODE_AUTO, null);
setUserOverridesHardKeyboardSetting();
}
}
// If the setting and the internal state are out of sync, set both to default
if (getSoftKeyboardValueFromSettings() != mSoftKeyboardShowMode) {
Slog.e(LOG_TAG, "Show IME setting inconsistent with internal state. Overwriting");
setSoftKeyboardModeLocked(SHOW_MODE_AUTO, null);
putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
SHOW_MODE_AUTO, mUserId);
}
}
boolean getBindInstantServiceAllowedLocked() {
return mBindInstantServiceAllowed;
}
/* Need to have a permission check on callee */
void setBindInstantServiceAllowedLocked(boolean allowed) {
mBindInstantServiceAllowed = allowed;
}
/**
* Returns binding service list.
*/
Set<ComponentName> getBindingServicesLocked() {
return mBindingServices;
}
/**
* Returns crashed service list.
*/
Set<ComponentName> getCrashedServicesLocked() {
return mCrashedServices;
}
/**
* Returns enabled service list.
*/
Set<ComponentName> getEnabledServicesLocked() {
return mEnabledServices;
}
/**
* Remove service from crashed service list if users disable it.
*/
void updateCrashedServicesIfNeededLocked() {
for (int i = 0, count = mInstalledServices.size(); i < count; i++) {
final AccessibilityServiceInfo installedService = mInstalledServices.get(i);
final ComponentName componentName = ComponentName.unflattenFromString(
installedService.getId());
if (mCrashedServices.contains(componentName)
&& !mEnabledServices.contains(componentName)) {
// Remove it from mCrashedServices since users toggle the switch bar to retry.
mCrashedServices.remove(componentName);
}
}
}
List<AccessibilityServiceConnection> getBoundServicesLocked() {
return mBoundServices;
}
int getClientStateLocked(boolean isUiAutomationRunning) {
int clientState = 0;
final boolean a11yEnabled = isUiAutomationRunning
|| isHandlingAccessibilityEventsLocked();
if (a11yEnabled) {
clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
}
// Touch exploration relies on enabled accessibility.
if (a11yEnabled && mIsTouchExplorationEnabled) {
clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
clientState |= AccessibilityManager.STATE_FLAG_DISPATCH_DOUBLE_TAP;
clientState |= AccessibilityManager.STATE_FLAG_REQUEST_MULTI_FINGER_GESTURES;
}
if (mIsTextHighContrastEnabled) {
clientState |= AccessibilityManager.STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED;
}
return clientState;
}
private void setUserOverridesHardKeyboardSetting() {
final int softKeyboardSetting = getSecureIntForUser(
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId);
putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
softKeyboardSetting | SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN,
mUserId);
}
private boolean hasUserOverriddenHardKeyboardSetting() {
final int softKeyboardSetting = getSecureIntForUser(
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId);
return (softKeyboardSetting & SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN)
!= 0;
}
private void setOriginalHardKeyboardValue(boolean originalHardKeyboardValue) {
final int oldSoftKeyboardSetting = getSecureIntForUser(
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId);
final int newSoftKeyboardSetting = oldSoftKeyboardSetting
& (~SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE)
| ((originalHardKeyboardValue) ? SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE : 0);
putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
newSoftKeyboardSetting, mUserId);
}
private void saveSoftKeyboardValueToSettings(int softKeyboardShowMode) {
final int oldSoftKeyboardSetting = getSecureIntForUser(
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId);
final int newSoftKeyboardSetting = oldSoftKeyboardSetting & (~SHOW_MODE_MASK)
| softKeyboardShowMode;
putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
newSoftKeyboardSetting, mUserId);
}
private int getSoftKeyboardValueFromSettings() {
return getSecureIntForUser(
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId)
& SHOW_MODE_MASK;
}
private boolean getOriginalHardKeyboardValue() {
return (getSecureIntForUser(
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId)
& SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE) != 0;
}
private void unbindAllServicesLocked() {
final List<AccessibilityServiceConnection> services = mBoundServices;
for (int count = services.size(); count > 0; count--) {
// When the service is unbound, it disappears from the list, so there's no need to
// keep track of the index
services.get(0).unbindLocked();
}
}
private int getSecureIntForUser(String key, int def, int userId) {
return Settings.Secure.getIntForUser(mContext.getContentResolver(), key, def, userId);
}
private void putSecureIntForUser(String key, int value, int userId) {
final long identity = Binder.clearCallingIdentity();
try {
Settings.Secure.putIntForUser(mContext.getContentResolver(), key, value, userId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.append("User state[");
pw.println();
pw.append(" attributes:{id=").append(String.valueOf(mUserId));
pw.append(", touchExplorationEnabled=").append(String.valueOf(mIsTouchExplorationEnabled));
pw.append(", serviceHandlesDoubleTap=")
.append(String.valueOf(mServiceHandlesDoubleTap));
pw.append(", requestMultiFingerGestures=")
.append(String.valueOf(mRequestMultiFingerGestures));
pw.append(", displayMagnificationEnabled=").append(String.valueOf(
mIsDisplayMagnificationEnabled));
pw.append(", autoclickEnabled=").append(String.valueOf(mIsAutoclickEnabled));
pw.append(", nonInteractiveUiTimeout=").append(String.valueOf(mNonInteractiveUiTimeout));
pw.append(", interactiveUiTimeout=").append(String.valueOf(mInteractiveUiTimeout));
pw.append(", installedServiceCount=").append(String.valueOf(mInstalledServices.size()));
pw.append("}");
pw.println();
pw.append(" shortcut key:{");
int size = mAccessibilityShortcutKeyTargets.size();
for (int i = 0; i < size; i++) {
final String componentId = mAccessibilityShortcutKeyTargets.valueAt(i);
pw.append(componentId);
if (i + 1 < size) {
pw.append(", ");
}
}
pw.println("}");
pw.append(" button:{");
size = mAccessibilityButtonTargets.size();
for (int i = 0; i < size; i++) {
final String componentId = mAccessibilityButtonTargets.valueAt(i);
pw.append(componentId);
if (i + 1 < size) {
pw.append(", ");
}
}
pw.println("}");
pw.append(" button target:{").append(mTargetAssignedToAccessibilityButton);
pw.println("}");
pw.append(" Bound services:{");
final int serviceCount = mBoundServices.size();
for (int j = 0; j < serviceCount; j++) {
if (j > 0) {
pw.append(", ");
pw.println();
pw.append(" ");
}
AccessibilityServiceConnection service = mBoundServices.get(j);
service.dump(fd, pw, args);
}
pw.println("}");
pw.append(" Enabled services:{");
Iterator<ComponentName> it = mEnabledServices.iterator();
if (it.hasNext()) {
ComponentName componentName = it.next();
pw.append(componentName.toShortString());
while (it.hasNext()) {
componentName = it.next();
pw.append(", ");
pw.append(componentName.toShortString());
}
}
pw.println("}");
pw.append(" Binding services:{");
it = mBindingServices.iterator();
if (it.hasNext()) {
ComponentName componentName = it.next();
pw.append(componentName.toShortString());
while (it.hasNext()) {
componentName = it.next();
pw.append(", ");
pw.append(componentName.toShortString());
}
}
pw.println("}");
pw.append(" Crashed services:{");
it = mCrashedServices.iterator();
if (it.hasNext()) {
ComponentName componentName = it.next();
pw.append(componentName.toShortString());
while (it.hasNext()) {
componentName = it.next();
pw.append(", ");
pw.append(componentName.toShortString());
}
}
pw.println("}]");
}
public boolean isAutoclickEnabledLocked() {
return mIsAutoclickEnabled;
}
public void setAutoclickEnabledLocked(boolean enabled) {
mIsAutoclickEnabled = enabled;
}
public boolean isDisplayMagnificationEnabledLocked() {
return mIsDisplayMagnificationEnabled;
}
public void setDisplayMagnificationEnabledLocked(boolean enabled) {
mIsDisplayMagnificationEnabled = enabled;
}
public boolean isFilterKeyEventsEnabledLocked() {
return mIsFilterKeyEventsEnabled;
}
public void setFilterKeyEventsEnabledLocked(boolean enabled) {
mIsFilterKeyEventsEnabled = enabled;
}
public int getInteractiveUiTimeoutLocked() {
return mInteractiveUiTimeout;
}
public void setInteractiveUiTimeoutLocked(int timeout) {
mInteractiveUiTimeout = timeout;
}
public int getLastSentClientStateLocked() {
return mLastSentClientState;
}
public void setLastSentClientStateLocked(int state) {
mLastSentClientState = state;
}
/**
* Returns true if navibar magnification or shortcut key magnification is enabled.
*/
public boolean isShortcutMagnificationEnabledLocked() {
return mAccessibilityShortcutKeyTargets.contains(MAGNIFICATION_CONTROLLER_NAME)
|| mAccessibilityButtonTargets.contains(MAGNIFICATION_CONTROLLER_NAME);
}
/**
* Disable both shortcuts' magnification function.
*/
public void disableShortcutMagnificationLocked() {
mAccessibilityShortcutKeyTargets.remove(MAGNIFICATION_CONTROLLER_NAME);
mAccessibilityButtonTargets.remove(MAGNIFICATION_CONTROLLER_NAME);
}
/**
* Returns a set which contains the flattened component names and the system class names
* assigned to the given shortcut.
*
* @param shortcutType The shortcut type.
* @return The array set of the strings
*/
public ArraySet<String> getShortcutTargetsLocked(@ShortcutType int shortcutType) {
if (shortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
return mAccessibilityShortcutKeyTargets;
} else if (shortcutType == ACCESSIBILITY_BUTTON) {
return mAccessibilityButtonTargets;
}
return null;
}
/**
* Whether or not the given shortcut target is installed in device.
*
* @param name The shortcut target name
* @return true if the shortcut target is installed.
*/
public boolean isShortcutTargetInstalledLocked(String name) {
if (TextUtils.isEmpty(name)) {
return false;
}
if (MAGNIFICATION_CONTROLLER_NAME.equals(name)) {
return true;
}
final ComponentName componentName = ComponentName.unflattenFromString(name);
if (componentName == null) {
return false;
}
if (AccessibilityShortcutController.getFrameworkShortcutFeaturesMap()
.containsKey(componentName)) {
return true;
}
if (getInstalledServiceInfoLocked(componentName) != null) {
return true;
}
for (int i = 0; i < mInstalledShortcuts.size(); i++) {
if (mInstalledShortcuts.get(i).getComponentName().equals(componentName)) {
return true;
}
}
return false;
}
/**
* Returns installed accessibility service info by the given service component name.
*/
public AccessibilityServiceInfo getInstalledServiceInfoLocked(ComponentName componentName) {
for (int i = 0; i < mInstalledServices.size(); i++) {
final AccessibilityServiceInfo serviceInfo = mInstalledServices.get(i);
if (serviceInfo.getComponentName().equals(componentName)) {
return serviceInfo;
}
}
return null;
}
/**
* Returns accessibility service connection by the given service component name.
*/
public AccessibilityServiceConnection getServiceConnectionLocked(ComponentName componentName) {
return mComponentNameToServiceMap.get(componentName);
}
public int getNonInteractiveUiTimeoutLocked() {
return mNonInteractiveUiTimeout;
}
public void setNonInteractiveUiTimeoutLocked(int timeout) {
mNonInteractiveUiTimeout = timeout;
}
public boolean isPerformGesturesEnabledLocked() {
return mIsPerformGesturesEnabled;
}
public void setPerformGesturesEnabledLocked(boolean enabled) {
mIsPerformGesturesEnabled = enabled;
}
public ComponentName getServiceChangingSoftKeyboardModeLocked() {
return mServiceChangingSoftKeyboardMode;
}
public void setServiceChangingSoftKeyboardModeLocked(
ComponentName serviceChangingSoftKeyboardMode) {
mServiceChangingSoftKeyboardMode = serviceChangingSoftKeyboardMode;
}
public boolean isTextHighContrastEnabledLocked() {
return mIsTextHighContrastEnabled;
}
public void setTextHighContrastEnabledLocked(boolean enabled) {
mIsTextHighContrastEnabled = enabled;
}
public boolean isTouchExplorationEnabledLocked() {
return mIsTouchExplorationEnabled;
}
public void setTouchExplorationEnabledLocked(boolean enabled) {
mIsTouchExplorationEnabled = enabled;
}
public boolean isServiceHandlesDoubleTapEnabledLocked() {
return mServiceHandlesDoubleTap;
}
public void setServiceHandlesDoubleTapLocked(boolean enabled) {
mServiceHandlesDoubleTap = enabled;
}
public boolean isMultiFingerGesturesEnabledLocked() {
return mRequestMultiFingerGestures;
}
public void setMultiFingerGesturesLocked(boolean enabled) {
mRequestMultiFingerGestures = enabled;
}
public int getUserInteractiveUiTimeoutLocked() {
return mUserInteractiveUiTimeout;
}
public void setUserInteractiveUiTimeoutLocked(int timeout) {
mUserInteractiveUiTimeout = timeout;
}
public int getUserNonInteractiveUiTimeoutLocked() {
return mUserNonInteractiveUiTimeout;
}
public void setUserNonInteractiveUiTimeoutLocked(int timeout) {
mUserNonInteractiveUiTimeout = timeout;
}
/**
* Gets a shortcut target which is assigned to the accessibility button by the chooser
* activity.
*
* @return The flattened component name or the system class name of the shortcut target.
*/
public String getTargetAssignedToAccessibilityButton() {
return mTargetAssignedToAccessibilityButton;
}
/**
* Sets a shortcut target which is assigned to the accessibility button by the chooser
* activity.
*
* @param target The flattened component name or the system class name of the shortcut target.
*/
public void setTargetAssignedToAccessibilityButton(String target) {
mTargetAssignedToAccessibilityButton = target;
}
/**
* Whether or not the given target name is contained in the shortcut collection. Since the
* component name string format could be short or long, this function un-flatten the component
* name from the string in {@code shortcutTargets} and compared with the given target name.
*
* @param shortcutTargets The shortcut type.
* @param targetName The target name.
* @return {@code true} if the target is in the shortcut collection.
*/
public static boolean doesShortcutTargetsStringContain(Collection<String> shortcutTargets,
String targetName) {
if (shortcutTargets == null || targetName == null) {
return false;
}
// Some system features, such as magnification, don't have component name. Using string
// compare first.
if (shortcutTargets.contains(targetName)) {
return true;
}
final ComponentName targetComponentName = ComponentName.unflattenFromString(targetName);
if (targetComponentName == null) {
return false;
}
for (String stringName : shortcutTargets) {
if (!TextUtils.isEmpty(stringName)
&& targetComponentName.equals(ComponentName.unflattenFromString(stringName))) {
return true;
}
}
return false;
}
}