OSDN Git Service

276a22f1ad95fc30a6d0d859f515442d96b86fda
[android-x86/packages-apps-Settings.git] / src / com / android / settings / AccessibilitySettings.java
1 /*
2  * Copyright (C) 2009 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.settings;
18
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;
38
39 import java.util.HashSet;
40 import java.util.LinkedHashMap;
41 import java.util.List;
42 import java.util.Map;
43
44 /**
45  * Activity with the accessibility settings.
46  */
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";
50
51     private final String TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX =
52         "toggle_accessibility_service_checkbox";
53
54     private static final String ACCESSIBILITY_SERVICES_CATEGORY =
55         "accessibility_services_category";
56
57     private CheckBoxPreference mToggleCheckBox;
58
59     private Map<String, ServiceInfo> mAccessibilityServices =
60         new LinkedHashMap<String, ServiceInfo>();
61
62     private TextUtils.SimpleStringSplitter mStringColonSplitter =
63         new TextUtils.SimpleStringSplitter(':');
64
65     private PreferenceGroup mAccessibilityServicesCategory;
66
67     @Override
68     protected void onCreate(Bundle icicle) {
69         super.onCreate(icicle);
70         addPreferencesFromResource(R.xml.accessibility_settings);
71
72         mToggleCheckBox = (CheckBoxPreference) findPreference(
73             TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX);
74
75         addAccessibilitServicePreferences();
76     }
77
78     @Override
79     protected void onResume() {
80         super.onResume();
81
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());
90             }
91         }
92
93         Map<String, ServiceInfo> accessibilityServices = mAccessibilityServices;
94
95         for (String key : accessibilityServices.keySet()) {
96             CheckBoxPreference preference = (CheckBoxPreference) findPreference(key);
97             if (preference != null) {
98                 preference.setChecked(enabled.contains(key));
99             }
100         }
101
102         int serviceState = Settings.Secure.getInt(getContentResolver(),
103             Settings.Secure.ACCESSIBILITY_ENABLED, 0);
104
105         if (!accessibilityServices.isEmpty()) {
106             if (serviceState == 1) {
107                 mToggleCheckBox.setChecked(true);
108             }
109             mToggleCheckBox.setEnabled(true);
110         } else {
111             if (serviceState == 1) {
112                 // no service and accessibility is enabled => disable
113                 Settings.Secure.putInt(getContentResolver(),
114                     Settings.Secure.ACCESSIBILITY_ENABLED, 0);
115             }
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();
120         }
121     }
122
123     @Override
124     protected void onPause() {
125         super.onPause();
126
127         persistEnabledAccessibilityServices();
128     }
129
130     @Override
131     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
132         final String key = preference.getKey();
133
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);
139         }
140
141         return super.onPreferenceTreeClick(preferenceScreen, preference);
142     }
143
144     /**
145      * Handles the change of the accessibility enabled setting state.
146      *
147      * @param preference The preference for enabling/disabling accessibility.
148      */
149     private void handleEnableAccessibilityStateChange(CheckBoxPreference preference) {
150         if (preference.isChecked()) {
151             Settings.Secure.putInt(getContentResolver(),
152                 Settings.Secure.ACCESSIBILITY_ENABLED, 1);
153         } else {
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))
159                 .setCancelable(true)
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);
165                         }
166                 })
167                 .setNegativeButton(android.R.string.cancel,
168                     new DialogInterface.OnClickListener() {
169                         public void onClick(DialogInterface dialog, int which) {
170                             checkBoxPreference.setChecked(true);
171                         }
172                 })
173                 .create();
174             dialog.show();
175         }
176     }
177
178     /**
179      * Handles the change of the preference for enabling/disabling an AccessibilityService.
180      *
181      * @param preference The preference.
182      */
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())))
192                 .setCancelable(true)
193                 .setPositiveButton(android.R.string.ok,
194                         new DialogInterface.OnClickListener() {
195                             public void onClick(DialogInterface dialog, int which) {
196                                 checkBoxPreference.setChecked(true);
197                                 persistEnabledAccessibilityServices();
198                             }
199                 })
200                 .setNegativeButton(android.R.string.cancel,
201                         new DialogInterface.OnClickListener() {
202                             public void onClick(DialogInterface dialog, int which) {
203                                 checkBoxPreference.setChecked(false);
204                             }
205                 })
206                 .create();
207             dialog.show();
208         } else {
209             persistEnabledAccessibilityServices();
210         }
211     }
212
213     /**
214      * Persists the Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES setting.
215      * The AccessibilityManagerService watches this property and manages the
216      * AccessibilityServices.
217      */
218     private void persistEnabledAccessibilityServices() {
219         StringBuilder builder = new StringBuilder(256);
220
221         int firstEnabled = -1;
222         for (String key : mAccessibilityServices.keySet()) {
223             CheckBoxPreference preference = (CheckBoxPreference) findPreference(key);
224             if (preference.isChecked()) {
225                  builder.append(key);
226                  builder.append(':');
227             }
228         }
229
230         Settings.Secure.putString(getContentResolver(),
231             Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, builder.toString());
232     }
233
234     /**
235      * Adds {@link CheckBoxPreference} for enabling or disabling an accessibility services.
236      */
237     private void addAccessibilitServicePreferences() {
238         AccessibilityManager accessibilityManager =
239             (AccessibilityManager) getSystemService(Service.ACCESSIBILITY_SERVICE);
240
241         List<ServiceInfo> installedServices = accessibilityManager.getAccessibilityServiceList();
242
243         mAccessibilityServicesCategory =
244             (PreferenceGroup) findPreference(ACCESSIBILITY_SERVICES_CATEGORY);
245
246         if (installedServices.isEmpty()) {
247             getPreferenceScreen().removePreference(mAccessibilityServicesCategory);
248             mAccessibilityServicesCategory = null;
249             return;
250         }
251
252         for (int i = 0, count = installedServices.size(); i < count; ++i) {
253             ServiceInfo serviceInfo = installedServices.get(i);
254             String key = serviceInfo.packageName + "/" + serviceInfo.name;
255
256             mAccessibilityServices.put(key, serviceInfo);
257
258             CheckBoxPreference preference = new CheckBoxPreference(this);
259             preference.setKey(key);
260             preference.setTitle(serviceInfo.loadLabel(getPackageManager()));
261             mAccessibilityServicesCategory.addPreference(preference);
262         }
263     }
264
265     /**
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.
269      */
270     private void displayNoAppsAlert() {
271         try {\r
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
276             return;\r
277         }
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);
281
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);
290                     finish();
291                 }
292             });
293
294         noAppsAlert.setNegativeButton(android.R.string.cancel,
295             new DialogInterface.OnClickListener() {
296                 public void onClick(DialogInterface dialog, int which) {
297                 }
298             });
299
300         noAppsAlert.show();
301     }
302 }