summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/accessibility/IAccessibilityManager.aidl4
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java81
-rw-r--r--services/core/java/com/android/server/policy/EnableAccessibilityController.java130
3 files changed, 154 insertions, 61 deletions
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 655c9b32c032..7f44bac8bc6f 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -59,4 +59,8 @@ interface IAccessibilityManager {
boolean touchExplorationEnabled);
IBinder getWindowToken(int windowId, int userId);
+
+ void enableAccessibilityService(in ComponentName service, int userId);
+
+ void disableAccessibilityService(in ComponentName service, int userId);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index c810e6c89c9f..2763ce383e89 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1812,6 +1812,87 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
return mKeyEventDispatcher;
}
+ /**
+ * Enables accessibility service specified by {@param componentName} for the {@param userId}.
+ */
+ public void enableAccessibilityService(ComponentName componentName, int userId) {
+ synchronized(mLock) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("only SYSTEM can call enableAccessibilityService.");
+ }
+
+ SettingsStringHelper settingsHelper = new SettingsStringHelper(
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, userId);
+ settingsHelper.addService(componentName);
+ settingsHelper.writeToSettings();
+
+ UserState userState = getUserStateLocked(userId);
+ if (userState.mEnabledServices.add(componentName)) {
+ onUserStateChangedLocked(userState);
+ }
+ }
+ }
+
+ /**
+ * Disables accessibility service specified by {@param componentName} for the {@param userId}.
+ */
+ public void disableAccessibilityService(ComponentName componentName, int userId) {
+ synchronized(mLock) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("only SYSTEM can call disableAccessibility");
+ }
+
+ SettingsStringHelper settingsHelper = new SettingsStringHelper(
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, userId);
+ settingsHelper.deleteService(componentName);
+ settingsHelper.writeToSettings();
+
+ UserState userState = getUserStateLocked(userId);
+ if (userState.mEnabledServices.remove(componentName)) {
+ onUserStateChangedLocked(userState);
+ }
+ }
+ }
+
+ private class SettingsStringHelper {
+ private static final String SETTINGS_DELIMITER = ":";
+ private ContentResolver mContentResolver;
+ private final String mSettingsName;
+ private Set<String> mServices;
+ private final int mUserId;
+
+ public SettingsStringHelper(String name, int userId) {
+ mUserId = userId;
+ mSettingsName = name;
+ mContentResolver = mContext.getContentResolver();
+ String servicesString = Settings.Secure.getStringForUser(
+ mContentResolver, mSettingsName, userId);
+ mServices = new HashSet();
+ if (!TextUtils.isEmpty(servicesString)) {
+ final TextUtils.SimpleStringSplitter colonSplitter =
+ new TextUtils.SimpleStringSplitter(SETTINGS_DELIMITER.charAt(0));
+ colonSplitter.setString(servicesString);
+ while (colonSplitter.hasNext()) {
+ final String serviceName = colonSplitter.next();
+ mServices.add(serviceName);
+ }
+ }
+ }
+
+ public void addService(ComponentName component) {
+ mServices.add(component.flattenToString());
+ }
+
+ public void deleteService(ComponentName component) {
+ mServices.remove(component.flattenToString());
+ }
+
+ public void writeToSettings() {
+ Settings.Secure.putStringForUser(mContentResolver, mSettingsName,
+ TextUtils.join(SETTINGS_DELIMITER, mServices), mUserId);
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
diff --git a/services/core/java/com/android/server/policy/EnableAccessibilityController.java b/services/core/java/com/android/server/policy/EnableAccessibilityController.java
index da9c001ea58f..6b203a910a25 100644
--- a/services/core/java/com/android/server/policy/EnableAccessibilityController.java
+++ b/services/core/java/com/android/server/policy/EnableAccessibilityController.java
@@ -16,7 +16,9 @@
package com.android.server.policy;
+import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -32,19 +34,25 @@ import android.os.ServiceManager;
import android.os.UserManager;
import android.provider.Settings;
import android.speech.tts.TextToSpeech;
+import android.util.Log;
import android.util.MathUtils;
import android.view.IWindowManager;
import android.view.MotionEvent;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+import android.view.WindowManagerInternal;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
import com.android.internal.R;
+import com.android.server.LocalServices;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class EnableAccessibilityController {
+ private static final String TAG = "EnableAccessibilityController";
private static final int SPEAK_WARNING_DELAY_MILLIS = 2000;
private static final int ENABLE_ACCESSIBILITY_DELAY_MILLIS = 6000;
@@ -75,9 +83,6 @@ public class EnableAccessibilityController {
}
};
- private final IWindowManager mWindowManager = IWindowManager.Stub.asInterface(
- ServiceManager.getService("window"));
-
private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager
.Stub.asInterface(ServiceManager.getService("accessibility"));
@@ -132,7 +137,7 @@ public class EnableAccessibilityController {
&& !getInstalledSpeakingAccessibilityServices(context).isEmpty();
}
- private static List<AccessibilityServiceInfo> getInstalledSpeakingAccessibilityServices(
+ public static List<AccessibilityServiceInfo> getInstalledSpeakingAccessibilityServices(
Context context) {
List<AccessibilityServiceInfo> services = new ArrayList<AccessibilityServiceInfo>();
services.addAll(AccessibilityManager.getInstance(context)
@@ -213,71 +218,74 @@ public class EnableAccessibilityController {
}
private void enableAccessibility() {
- List<AccessibilityServiceInfo> services = getInstalledSpeakingAccessibilityServices(
- mContext);
- if (services.isEmpty()) {
- return;
+ if (enableAccessibility(mContext)) {
+ mOnAccessibilityEnabledCallback.run();
+ }
+ }
+
+ public static boolean enableAccessibility(Context context) {
+ final IAccessibilityManager accessibilityManager = IAccessibilityManager
+ .Stub.asInterface(ServiceManager.getService("accessibility"));
+ final WindowManagerInternal windowManager = LocalServices.getService(
+ WindowManagerInternal.class);
+ final UserManager userManager = (UserManager) context.getSystemService(
+ Context.USER_SERVICE);
+ ComponentName componentName = getInstalledSpeakingAccessibilityServiceComponent(context);
+ if (componentName == null) {
+ return false;
}
- boolean keyguardLocked = false;
+
+ boolean keyguardLocked = windowManager.isKeyguardLocked();
+ final boolean hasMoreThanOneUser = userManager.getUsers().size() > 1;
try {
- keyguardLocked = mWindowManager.isKeyguardLocked();
- } catch (RemoteException re) {
- /* ignore */
+ if (!keyguardLocked || !hasMoreThanOneUser) {
+ final int userId = ActivityManager.getCurrentUser();
+ accessibilityManager.enableAccessibilityService(componentName, userId);
+ } else if (keyguardLocked) {
+ accessibilityManager.temporaryEnableAccessibilityStateUntilKeyguardRemoved(
+ componentName, true /* enableTouchExploration */);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "cannot enable accessibilty: " + e);
}
- final boolean hasMoreThanOneUser = mUserManager.getUsers().size() > 1;
+ return true;
+ }
- AccessibilityServiceInfo service = services.get(0);
- boolean enableTouchExploration = (service.flags
- & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
- // Try to find a service supporting explore by touch.
- if (!enableTouchExploration) {
- final int serviceCount = services.size();
- for (int i = 1; i < serviceCount; i++) {
- AccessibilityServiceInfo candidate = services.get(i);
- if ((candidate.flags & AccessibilityServiceInfo
- .FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0) {
- enableTouchExploration = true;
- service = candidate;
- break;
- }
- }
+ public static void disableAccessibility(Context context) {
+ final IAccessibilityManager accessibilityManager = IAccessibilityManager
+ .Stub.asInterface(ServiceManager.getService("accessibility"));
+ ComponentName componentName = getInstalledSpeakingAccessibilityServiceComponent(context);
+ if (componentName == null) {
+ return;
}
- ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
- ComponentName componentName = new ComponentName(serviceInfo.packageName, serviceInfo.name);
- if (!keyguardLocked || !hasMoreThanOneUser) {
- final int userId = ActivityManager.getCurrentUser();
- String enabledServiceString = componentName.flattenToString();
- ContentResolver resolver = mContext.getContentResolver();
- // Enable one speaking accessibility service.
- Settings.Secure.putStringForUser(resolver,
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
- enabledServiceString, userId);
- // Allow the services we just enabled to toggle touch exploration.
- Settings.Secure.putStringForUser(resolver,
- Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
- enabledServiceString, userId);
- // Enable touch exploration.
- if (enableTouchExploration) {
- Settings.Secure.putIntForUser(resolver, Settings.Secure.TOUCH_EXPLORATION_ENABLED,
- 1, userId);
- }
- // Enable accessibility script injection (AndroidVox) for web content.
- Settings.Secure.putIntForUser(resolver, Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION,
- 1, userId);
- // Turn on accessibility mode last.
- Settings.Secure.putIntForUser(resolver, Settings.Secure.ACCESSIBILITY_ENABLED,
- 1, userId);
- } else if (keyguardLocked) {
- try {
- mAccessibilityManager.temporaryEnableAccessibilityStateUntilKeyguardRemoved(
- componentName, enableTouchExploration);
- } catch (RemoteException re) {
- /* ignore */
- }
+ final int userId = ActivityManager.getCurrentUser();
+ try {
+ accessibilityManager.disableAccessibilityService(componentName, userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "cannot disable accessibility " + e);
+ }
+ }
+
+ public static boolean isAccessibilityEnabled(Context context) {
+ final AccessibilityManager accessibilityManager =
+ context.getSystemService(AccessibilityManager.class);
+ List enabledServices = accessibilityManager.getEnabledAccessibilityServiceList(
+ AccessibilityServiceInfo.FEEDBACK_SPOKEN);
+ return enabledServices != null && !enabledServices.isEmpty();
+ }
+
+ @Nullable
+ public static ComponentName getInstalledSpeakingAccessibilityServiceComponent(
+ Context context) {
+ List<AccessibilityServiceInfo> services =
+ getInstalledSpeakingAccessibilityServices(context);
+ if (services.isEmpty()) {
+ return null;
}
- mOnAccessibilityEnabledCallback.run();
+ ServiceInfo serviceInfo = services.get(0).getResolveInfo().serviceInfo;
+ return new ComponentName(serviceInfo.packageName, serviceInfo.name);
}
}