blob: e50b010d691ad8ff0224221b1e64f55ad538a014 [file] [log] [blame]
Peter_Liangdfe6f9232020-03-05 12:04:13 +08001/*
2 * Copyright (C) 2020 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
17package com.android.internal.accessibility.util;
Peter_Liangfbad5482020-04-08 19:32:53 +080018
Peter_Liang293e32b2020-04-13 17:42:04 +080019import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
Peter_Liangdfe6f9232020-03-05 12:04:13 +080020import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR;
21
22import android.accessibilityservice.AccessibilityServiceInfo;
Peter_Liang8b7c9da2020-04-08 16:56:59 +080023import android.annotation.NonNull;
Peter_Liangdfe6f9232020-03-05 12:04:13 +080024import android.content.ComponentName;
25import android.content.Context;
26import android.os.Build;
27import android.os.UserHandle;
28import android.provider.Settings;
29import android.text.TextUtils;
30import android.util.ArraySet;
Peter_Liangfbad5482020-04-08 19:32:53 +080031import android.view.accessibility.AccessibilityManager;
Peter_Liangdfe6f9232020-03-05 12:04:13 +080032
33import java.util.Collections;
34import java.util.HashSet;
Peter_Liangfbad5482020-04-08 19:32:53 +080035import java.util.List;
Peter_Liangdfe6f9232020-03-05 12:04:13 +080036import java.util.Set;
37
38/**
39 * Collection of utilities for accessibility service.
40 */
41public final class AccessibilityUtils {
42 private AccessibilityUtils() {}
43
44 /**
45 * Returns the set of enabled accessibility services for userId. If there are no
46 * services, it returns the unmodifiable {@link Collections#emptySet()}.
47 */
48 public static Set<ComponentName> getEnabledServicesFromSettings(Context context, int userId) {
49 final String enabledServicesSetting = Settings.Secure.getStringForUser(
50 context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
51 userId);
52 if (TextUtils.isEmpty(enabledServicesSetting)) {
53 return Collections.emptySet();
54 }
55
56 final Set<ComponentName> enabledServices = new HashSet<>();
57 final TextUtils.StringSplitter colonSplitter =
58 new TextUtils.SimpleStringSplitter(SERVICES_SEPARATOR);
59 colonSplitter.setString(enabledServicesSetting);
60
61 for (String componentNameString : colonSplitter) {
62 final ComponentName enabledService = ComponentName.unflattenFromString(
63 componentNameString);
64 if (enabledService != null) {
65 enabledServices.add(enabledService);
66 }
67 }
68
69 return enabledServices;
70 }
71
72 /**
73 * Changes an accessibility component's state.
74 */
75 public static void setAccessibilityServiceState(Context context, ComponentName componentName,
76 boolean enabled) {
77 setAccessibilityServiceState(context, componentName, enabled, UserHandle.myUserId());
78 }
79
80 /**
81 * Changes an accessibility component's state for {@param userId}.
82 */
83 public static void setAccessibilityServiceState(Context context, ComponentName componentName,
84 boolean enabled, int userId) {
85 Set<ComponentName> enabledServices = getEnabledServicesFromSettings(
86 context, userId);
87
88 if (enabledServices.isEmpty()) {
89 enabledServices = new ArraySet<>(/* capacity= */ 1);
90 }
91
92 if (enabled) {
93 enabledServices.add(componentName);
94 } else {
95 enabledServices.remove(componentName);
96 }
97
98 final StringBuilder enabledServicesBuilder = new StringBuilder();
99 for (ComponentName enabledService : enabledServices) {
100 enabledServicesBuilder.append(enabledService.flattenToString());
101 enabledServicesBuilder.append(
102 SERVICES_SEPARATOR);
103 }
104
105 final int enabledServicesBuilderLength = enabledServicesBuilder.length();
106 if (enabledServicesBuilderLength > 0) {
107 enabledServicesBuilder.deleteCharAt(enabledServicesBuilderLength - 1);
108 }
109
110 Settings.Secure.putStringForUser(context.getContentResolver(),
111 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
112 enabledServicesBuilder.toString(), userId);
113 }
114
115 /**
116 * Gets the corresponding fragment type of a given accessibility service.
117 *
118 * @param accessibilityServiceInfo The accessibilityService's info.
Peter_Liang293e32b2020-04-13 17:42:04 +0800119 * @return int from {@link AccessibilityFragmentType}.
Peter_Liangdfe6f9232020-03-05 12:04:13 +0800120 */
Peter_Liang293e32b2020-04-13 17:42:04 +0800121 public static @AccessibilityFragmentType int getAccessibilityServiceFragmentType(
Peter_Liang8b7c9da2020-04-08 16:56:59 +0800122 @NonNull AccessibilityServiceInfo accessibilityServiceInfo) {
Peter_Liangdfe6f9232020-03-05 12:04:13 +0800123 final int targetSdk = accessibilityServiceInfo.getResolveInfo()
124 .serviceInfo.applicationInfo.targetSdkVersion;
125 final boolean requestA11yButton = (accessibilityServiceInfo.flags
126 & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
127
128 if (targetSdk <= Build.VERSION_CODES.Q) {
Peter_Liang293e32b2020-04-13 17:42:04 +0800129 return AccessibilityFragmentType.VOLUME_SHORTCUT_TOGGLE;
Peter_Liangdfe6f9232020-03-05 12:04:13 +0800130 }
131 return requestA11yButton
Peter_Liang293e32b2020-04-13 17:42:04 +0800132 ? AccessibilityFragmentType.INVISIBLE_TOGGLE
133 : AccessibilityFragmentType.TOGGLE;
Peter_Liangdfe6f9232020-03-05 12:04:13 +0800134 }
Peter_Liangfbad5482020-04-08 19:32:53 +0800135
136 /**
137 * Returns if a {@code componentId} service is enabled.
138 *
139 * @param context The current context.
140 * @param componentId The component id that need to be checked.
141 * @return {@code true} if a {@code componentId} service is enabled.
142 */
143 public static boolean isAccessibilityServiceEnabled(Context context,
144 @NonNull String componentId) {
145 final AccessibilityManager am = context.getSystemService(AccessibilityManager.class);
146 final List<AccessibilityServiceInfo> enabledServices =
147 am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
148
149 for (AccessibilityServiceInfo info : enabledServices) {
150 final String id = info.getComponentName().flattenToString();
151 if (id.equals(componentId)) {
152 return true;
153 }
154 }
155
156 return false;
157 }
Peter_Liangdfe6f9232020-03-05 12:04:13 +0800158}