2 * Copyright (C) 2009 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings;
19 import android.app.AlertDialog;
20 import android.app.Service;
21 import android.content.DialogInterface;
22 import android.content.Intent;
23 import android.content.pm.ApplicationInfo;
24 import android.content.pm.PackageManager;
25 import android.content.pm.PackageManager.NameNotFoundException;
26 import android.content.pm.ServiceInfo;
27 import android.net.Uri;
28 import android.os.Bundle;
29 import android.os.SystemProperties;
30 import android.preference.CheckBoxPreference;
31 import android.preference.Preference;
32 import android.preference.PreferenceActivity;
33 import android.preference.PreferenceGroup;
34 import android.preference.PreferenceScreen;
35 import android.provider.Settings;
36 import android.text.TextUtils;
37 import android.view.accessibility.AccessibilityManager;
39 import java.util.HashSet;
40 import java.util.LinkedHashMap;
41 import java.util.List;
45 * Activity with the accessibility settings.
47 public class AccessibilitySettings extends PreferenceActivity {
48 private static final String DEFAULT_SCREENREADER_MARKET_LINK =
49 "market://search?q=pname:com.google.android.marvin.talkback";
51 private final String TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX =
52 "toggle_accessibility_service_checkbox";
54 private static final String ACCESSIBILITY_SERVICES_CATEGORY =
55 "accessibility_services_category";
57 private CheckBoxPreference mToggleCheckBox;
59 private Map<String, ServiceInfo> mAccessibilityServices =
60 new LinkedHashMap<String, ServiceInfo>();
62 private TextUtils.SimpleStringSplitter mStringColonSplitter =
63 new TextUtils.SimpleStringSplitter(':');
65 private PreferenceGroup mAccessibilityServicesCategory;
68 protected void onCreate(Bundle icicle) {
69 super.onCreate(icicle);
70 addPreferencesFromResource(R.xml.accessibility_settings);
72 mToggleCheckBox = (CheckBoxPreference) findPreference(
73 TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX);
75 addAccessibilitServicePreferences();
79 protected void onResume() {
82 final HashSet<String> enabled = new HashSet<String>();
83 String settingValue = Settings.Secure.getString(getContentResolver(),
84 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
85 if (settingValue != null) {
86 TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
87 splitter.setString(settingValue);
88 while (splitter.hasNext()) {
89 enabled.add(splitter.next());
93 Map<String, ServiceInfo> accessibilityServices = mAccessibilityServices;
95 for (String key : accessibilityServices.keySet()) {
96 CheckBoxPreference preference = (CheckBoxPreference) findPreference(key);
97 if (preference != null) {
98 preference.setChecked(enabled.contains(key));
102 int serviceState = Settings.Secure.getInt(getContentResolver(),
103 Settings.Secure.ACCESSIBILITY_ENABLED, 0);
105 if (!accessibilityServices.isEmpty()) {
106 if (serviceState == 1) {
107 mToggleCheckBox.setChecked(true);
109 mToggleCheckBox.setEnabled(true);
111 if (serviceState == 1) {
112 // no service and accessibility is enabled => disable
113 Settings.Secure.putInt(getContentResolver(),
114 Settings.Secure.ACCESSIBILITY_ENABLED, 0);
116 mToggleCheckBox.setEnabled(false);
117 // Notify user that they do not have any accessibility apps
118 // installed and direct them to Market to get TalkBack
119 displayNoAppsAlert();
124 protected void onPause() {
127 persistEnabledAccessibilityServices();
131 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
132 final String key = preference.getKey();
134 if (TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX.equals(key)) {
135 boolean isChecked = ((CheckBoxPreference) preference).isChecked();
136 handleEnableAccessibilityStateChange((CheckBoxPreference) preference);
137 } else if (preference instanceof CheckBoxPreference) {
138 handleEnableAccessibilityServiceStateChange((CheckBoxPreference) preference);
141 return super.onPreferenceTreeClick(preferenceScreen, preference);
145 * Handles the change of the accessibility enabled setting state.
147 * @param preference The preference for enabling/disabling accessibility.
149 private void handleEnableAccessibilityStateChange(CheckBoxPreference preference) {
150 if (preference.isChecked()) {
151 Settings.Secure.putInt(getContentResolver(),
152 Settings.Secure.ACCESSIBILITY_ENABLED, 1);
154 final CheckBoxPreference checkBoxPreference = preference;
155 AlertDialog dialog = (new AlertDialog.Builder(this))
156 .setTitle(android.R.string.dialog_alert_title)
157 .setIcon(android.R.drawable.ic_dialog_alert)
158 .setMessage(getString(R.string.accessibility_service_disable_warning))
160 .setPositiveButton(android.R.string.ok,
161 new DialogInterface.OnClickListener() {
162 public void onClick(DialogInterface dialog, int which) {
163 Settings.Secure.putInt(getContentResolver(),
164 Settings.Secure.ACCESSIBILITY_ENABLED, 0);
167 .setNegativeButton(android.R.string.cancel,
168 new DialogInterface.OnClickListener() {
169 public void onClick(DialogInterface dialog, int which) {
170 checkBoxPreference.setChecked(true);
179 * Handles the change of the preference for enabling/disabling an AccessibilityService.
181 * @param preference The preference.
183 private void handleEnableAccessibilityServiceStateChange(CheckBoxPreference preference) {
184 if (preference.isChecked()) {
185 final CheckBoxPreference checkBoxPreference = preference;
186 AlertDialog dialog = (new AlertDialog.Builder(this))
187 .setTitle(android.R.string.dialog_alert_title)
188 .setIcon(android.R.drawable.ic_dialog_alert)
189 .setMessage(getString(R.string.accessibility_service_security_warning,
190 mAccessibilityServices.get(preference.getKey())
191 .applicationInfo.loadLabel(getPackageManager())))
193 .setPositiveButton(android.R.string.ok,
194 new DialogInterface.OnClickListener() {
195 public void onClick(DialogInterface dialog, int which) {
196 checkBoxPreference.setChecked(true);
197 persistEnabledAccessibilityServices();
200 .setNegativeButton(android.R.string.cancel,
201 new DialogInterface.OnClickListener() {
202 public void onClick(DialogInterface dialog, int which) {
203 checkBoxPreference.setChecked(false);
209 persistEnabledAccessibilityServices();
214 * Persists the Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES setting.
215 * The AccessibilityManagerService watches this property and manages the
216 * AccessibilityServices.
218 private void persistEnabledAccessibilityServices() {
219 StringBuilder builder = new StringBuilder(256);
221 int firstEnabled = -1;
222 for (String key : mAccessibilityServices.keySet()) {
223 CheckBoxPreference preference = (CheckBoxPreference) findPreference(key);
224 if (preference.isChecked()) {
230 Settings.Secure.putString(getContentResolver(),
231 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, builder.toString());
235 * Adds {@link CheckBoxPreference} for enabling or disabling an accessibility services.
237 private void addAccessibilitServicePreferences() {
238 AccessibilityManager accessibilityManager =
239 (AccessibilityManager) getSystemService(Service.ACCESSIBILITY_SERVICE);
241 List<ServiceInfo> installedServices = accessibilityManager.getAccessibilityServiceList();
243 mAccessibilityServicesCategory =
244 (PreferenceGroup) findPreference(ACCESSIBILITY_SERVICES_CATEGORY);
246 if (installedServices.isEmpty()) {
247 getPreferenceScreen().removePreference(mAccessibilityServicesCategory);
248 mAccessibilityServicesCategory = null;
252 for (int i = 0, count = installedServices.size(); i < count; ++i) {
253 ServiceInfo serviceInfo = installedServices.get(i);
254 String key = serviceInfo.packageName + "/" + serviceInfo.name;
256 mAccessibilityServices.put(key, serviceInfo);
258 CheckBoxPreference preference = new CheckBoxPreference(this);
259 preference.setKey(key);
260 preference.setTitle(serviceInfo.loadLabel(getPackageManager()));
261 mAccessibilityServicesCategory.addPreference(preference);
266 * Displays a message telling the user that they do not have any accessibility
267 * related apps installed and that they can get TalkBack (Google's free screen
268 * reader) from Market.
270 private void displayNoAppsAlert() {
272 PackageManager pm = getPackageManager();
\r
273 ApplicationInfo info = pm.getApplicationInfo("com.android.vending", 0);
\r
274 } catch (NameNotFoundException e) {
275 // This is a no-op if the user does not have Android Market
\r
278 AlertDialog.Builder noAppsAlert = new AlertDialog.Builder(this);
279 noAppsAlert.setTitle(R.string.accessibility_service_no_apps_title);
280 noAppsAlert.setMessage(R.string.accessibility_service_no_apps_message);
282 noAppsAlert.setPositiveButton(android.R.string.ok,
283 new DialogInterface.OnClickListener() {
284 public void onClick(DialogInterface dialog, int which) {
285 String screenreaderMarketLink =
286 SystemProperties.get("ro.screenreader.market", DEFAULT_SCREENREADER_MARKET_LINK);
287 Uri marketUri = Uri.parse(screenreaderMarketLink);
288 Intent marketIntent = new Intent(Intent.ACTION_VIEW, marketUri);
289 startActivity(marketIntent);
294 noAppsAlert.setNegativeButton(android.R.string.cancel,
295 new DialogInterface.OnClickListener() {
296 public void onClick(DialogInterface dialog, int which) {