OSDN Git Service

am 8815f032: Merge "Always set right auth_type value in apn."
[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.PreferenceCategory;
34 import android.preference.PreferenceGroup;
35 import android.preference.PreferenceScreen;
36 import android.provider.Settings;
37 import android.text.TextUtils;
38 import android.view.KeyCharacterMap;
39 import android.view.KeyEvent;
40 import android.view.accessibility.AccessibilityManager;
41
42 import java.util.HashSet;
43 import java.util.LinkedHashMap;
44 import java.util.List;
45 import java.util.Map;
46
47 /**
48  * Activity with the accessibility settings.
49  */
50 public class AccessibilitySettings extends PreferenceActivity {
51     private static final String DEFAULT_SCREENREADER_MARKET_LINK =
52         "market://search?q=pname:com.google.android.marvin.talkback";
53
54     private final String TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX =
55         "toggle_accessibility_service_checkbox";
56
57     private static final String ACCESSIBILITY_SERVICES_CATEGORY =
58         "accessibility_services_category";
59
60     private static final String POWER_BUTTON_CATEGORY =
61         "power_button_category";
62
63     private final String POWER_BUTTON_ENDS_CALL_CHECKBOX =
64         "power_button_ends_call";
65
66     private CheckBoxPreference mToggleCheckBox;
67
68     private PreferenceCategory mPowerButtonCategory;
69     private CheckBoxPreference mPowerButtonEndsCallCheckBox;
70
71     private Map<String, ServiceInfo> mAccessibilityServices =
72         new LinkedHashMap<String, ServiceInfo>();
73
74     private TextUtils.SimpleStringSplitter mStringColonSplitter =
75         new TextUtils.SimpleStringSplitter(':');
76
77     private PreferenceGroup mAccessibilityServicesCategory;
78
79     @Override
80     protected void onCreate(Bundle icicle) {
81         super.onCreate(icicle);
82         addPreferencesFromResource(R.xml.accessibility_settings);
83
84         mToggleCheckBox = (CheckBoxPreference) findPreference(
85             TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX);
86
87         mPowerButtonCategory = (PreferenceCategory) findPreference(POWER_BUTTON_CATEGORY);
88         mPowerButtonEndsCallCheckBox = (CheckBoxPreference) findPreference(
89             POWER_BUTTON_ENDS_CALL_CHECKBOX);
90
91         addAccessibilitServicePreferences();
92     }
93
94     @Override
95     protected void onResume() {
96         super.onResume();
97
98         final HashSet<String> enabled = new HashSet<String>();
99         String settingValue = Settings.Secure.getString(getContentResolver(),
100                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
101         if (settingValue != null) {
102             TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
103             splitter.setString(settingValue);
104             while (splitter.hasNext()) {
105                 enabled.add(splitter.next());
106             }
107         }
108
109         Map<String, ServiceInfo> accessibilityServices = mAccessibilityServices;
110
111         for (String key : accessibilityServices.keySet()) {
112             CheckBoxPreference preference = (CheckBoxPreference) findPreference(key);
113             if (preference != null) {
114                 preference.setChecked(enabled.contains(key));
115             }
116         }
117
118         int serviceState = Settings.Secure.getInt(getContentResolver(),
119             Settings.Secure.ACCESSIBILITY_ENABLED, 0);
120
121         if (!accessibilityServices.isEmpty()) {
122             if (serviceState == 1) {
123                 mToggleCheckBox.setChecked(true);
124             } else {
125                 setAccessibilityServicePreferencesState(false);
126             }
127             mToggleCheckBox.setEnabled(true);
128         } else {
129             if (serviceState == 1) {
130                 // no service and accessibility is enabled => disable
131                 Settings.Secure.putInt(getContentResolver(),
132                     Settings.Secure.ACCESSIBILITY_ENABLED, 0);
133             }
134             mToggleCheckBox.setEnabled(false);
135             // Notify user that they do not have any accessibility apps
136             // installed and direct them to Market to get TalkBack
137             displayNoAppsAlert();
138         }
139
140         if (KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)) {
141             int incallPowerBehavior = Settings.Secure.getInt(getContentResolver(),
142                     Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
143                     Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT);
144             // The checkbox is labeled "Power button ends call"; thus the in-call
145             // Power button behavior is INCALL_POWER_BUTTON_BEHAVIOR_HANGUP if
146             // checked, and INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF if unchecked.
147             boolean powerButtonCheckboxEnabled =
148                     (incallPowerBehavior == Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP);
149             mPowerButtonEndsCallCheckBox.setChecked(powerButtonCheckboxEnabled);
150             mPowerButtonEndsCallCheckBox.setEnabled(true);
151         } else {
152             // No POWER key on the current device; this entire category is irrelevant.
153             getPreferenceScreen().removePreference(mPowerButtonCategory);
154         }
155     }
156
157     @Override
158     protected void onPause() {
159         super.onPause();
160
161         persistEnabledAccessibilityServices();
162     }
163
164     /**
165      * Sets the state of the preferences for enabling/disabling
166      * AccessibilityServices.
167      *
168      * @param isEnabled If to enable or disable the preferences.
169      */
170     private void setAccessibilityServicePreferencesState(boolean isEnabled) {
171         if (mAccessibilityServicesCategory == null) {
172             return;
173         }
174
175         int count = mAccessibilityServicesCategory.getPreferenceCount();
176         for (int i = 0; i < count; i++) {
177             Preference pref = mAccessibilityServicesCategory.getPreference(i);
178             pref.setEnabled(isEnabled);
179         }
180     }
181
182     @Override
183     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
184         final String key = preference.getKey();
185
186         if (TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX.equals(key)) {
187             boolean isChecked = ((CheckBoxPreference) preference).isChecked();
188             handleEnableAccessibilityStateChange((CheckBoxPreference) preference);
189         } else if (POWER_BUTTON_ENDS_CALL_CHECKBOX.equals(key)) {
190             boolean isChecked = ((CheckBoxPreference) preference).isChecked();
191             // The checkbox is labeled "Power button ends call"; thus the in-call
192             // Power button behavior is INCALL_POWER_BUTTON_BEHAVIOR_HANGUP if
193             // checked, and INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF if unchecked.
194             Settings.Secure.putInt(getContentResolver(),
195                     Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
196                     (isChecked ? Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP
197                             : Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF));
198         } else if (preference instanceof CheckBoxPreference) {
199             handleEnableAccessibilityServiceStateChange((CheckBoxPreference) preference);
200         }
201
202         return super.onPreferenceTreeClick(preferenceScreen, preference);
203     }
204
205     /**
206      * Handles the change of the accessibility enabled setting state.
207      *
208      * @param preference The preference for enabling/disabling accessibility.
209      */
210     private void handleEnableAccessibilityStateChange(CheckBoxPreference preference) {
211         if (preference.isChecked()) {
212             Settings.Secure.putInt(getContentResolver(),
213                 Settings.Secure.ACCESSIBILITY_ENABLED, 1);
214             setAccessibilityServicePreferencesState(true);
215         } else {
216             final CheckBoxPreference checkBoxPreference = preference;
217             AlertDialog dialog = (new AlertDialog.Builder(this))
218                 .setTitle(android.R.string.dialog_alert_title)
219                 .setIcon(android.R.drawable.ic_dialog_alert)
220                 .setMessage(getString(R.string.accessibility_service_disable_warning))
221                 .setCancelable(true)
222                 .setPositiveButton(android.R.string.ok,
223                     new DialogInterface.OnClickListener() {
224                         public void onClick(DialogInterface dialog, int which) {
225                             Settings.Secure.putInt(getContentResolver(),
226                                 Settings.Secure.ACCESSIBILITY_ENABLED, 0);
227                             setAccessibilityServicePreferencesState(false);
228                         }
229                 })
230                 .setNegativeButton(android.R.string.cancel,
231                     new DialogInterface.OnClickListener() {
232                         public void onClick(DialogInterface dialog, int which) {
233                             checkBoxPreference.setChecked(true);
234                         }
235                 })
236                 .create();
237             dialog.show();
238         }
239     }
240
241     /**
242      * Handles the change of the preference for enabling/disabling an AccessibilityService.
243      *
244      * @param preference The preference.
245      */
246     private void handleEnableAccessibilityServiceStateChange(CheckBoxPreference preference) {
247         if (preference.isChecked()) {
248             final CheckBoxPreference checkBoxPreference = preference;
249             AlertDialog dialog = (new AlertDialog.Builder(this))
250                 .setTitle(android.R.string.dialog_alert_title)
251                 .setIcon(android.R.drawable.ic_dialog_alert)
252                 .setMessage(getString(R.string.accessibility_service_security_warning,
253                     mAccessibilityServices.get(preference.getKey())
254                     .applicationInfo.loadLabel(getPackageManager())))
255                 .setCancelable(true)
256                 .setPositiveButton(android.R.string.ok,
257                         new DialogInterface.OnClickListener() {
258                             public void onClick(DialogInterface dialog, int which) {
259                                 checkBoxPreference.setChecked(true);
260                                 persistEnabledAccessibilityServices();
261                             }
262                 })
263                 .setNegativeButton(android.R.string.cancel,
264                         new DialogInterface.OnClickListener() {
265                             public void onClick(DialogInterface dialog, int which) {
266                                 checkBoxPreference.setChecked(false);
267                             }
268                 })
269                 .create();
270             dialog.show();
271         } else {
272             persistEnabledAccessibilityServices();
273         }
274     }
275
276     /**
277      * Persists the Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES setting.
278      * The AccessibilityManagerService watches this property and manages the
279      * AccessibilityServices.
280      */
281     private void persistEnabledAccessibilityServices() {
282         StringBuilder builder = new StringBuilder(256);
283
284         int firstEnabled = -1;
285         for (String key : mAccessibilityServices.keySet()) {
286             CheckBoxPreference preference = (CheckBoxPreference) findPreference(key);
287             if (preference.isChecked()) {
288                  builder.append(key);
289                  builder.append(':');
290             }
291         }
292
293         Settings.Secure.putString(getContentResolver(),
294             Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, builder.toString());
295     }
296
297     /**
298      * Adds {@link CheckBoxPreference} for enabling or disabling an accessibility services.
299      */
300     private void addAccessibilitServicePreferences() {
301         AccessibilityManager accessibilityManager =
302             (AccessibilityManager) getSystemService(Service.ACCESSIBILITY_SERVICE);
303
304         List<ServiceInfo> installedServices = accessibilityManager.getAccessibilityServiceList();
305
306         mAccessibilityServicesCategory =
307             (PreferenceGroup) findPreference(ACCESSIBILITY_SERVICES_CATEGORY);
308
309         if (installedServices.isEmpty()) {
310             getPreferenceScreen().removePreference(mAccessibilityServicesCategory);
311             mAccessibilityServicesCategory = null;
312             return;
313         }
314
315         for (int i = 0, count = installedServices.size(); i < count; ++i) {
316             ServiceInfo serviceInfo = installedServices.get(i);
317             String key = serviceInfo.packageName + "/" + serviceInfo.name;
318
319             mAccessibilityServices.put(key, serviceInfo);
320
321             CheckBoxPreference preference = new CheckBoxPreference(this);
322             preference.setKey(key);
323             preference.setTitle(serviceInfo.loadLabel(getPackageManager()));
324             mAccessibilityServicesCategory.addPreference(preference);
325         }
326     }
327
328     /**
329      * Displays a message telling the user that they do not have any accessibility
330      * related apps installed and that they can get TalkBack (Google's free screen
331      * reader) from Market.
332      */
333     private void displayNoAppsAlert() {
334         try {
335             PackageManager pm = getPackageManager();
336             ApplicationInfo info = pm.getApplicationInfo("com.android.vending", 0);
337         } catch (NameNotFoundException e) {
338             // This is a no-op if the user does not have Android Market
339             return;
340         }
341         AlertDialog.Builder noAppsAlert = new AlertDialog.Builder(this);
342         noAppsAlert.setTitle(R.string.accessibility_service_no_apps_title);
343         noAppsAlert.setMessage(R.string.accessibility_service_no_apps_message);
344
345         noAppsAlert.setPositiveButton(android.R.string.ok,
346             new DialogInterface.OnClickListener() {
347                 public void onClick(DialogInterface dialog, int which) {
348                     String screenreaderMarketLink =
349                         SystemProperties.get("ro.screenreader.market",
350                                 DEFAULT_SCREENREADER_MARKET_LINK);
351                     Uri marketUri = Uri.parse(screenreaderMarketLink);
352                     Intent marketIntent = new Intent(Intent.ACTION_VIEW, marketUri);
353                     startActivity(marketIntent);
354                     finish();
355                 }
356             });
357
358         noAppsAlert.setNegativeButton(android.R.string.cancel,
359             new DialogInterface.OnClickListener() {
360                 public void onClick(DialogInterface dialog, int which) {
361                 }
362             });
363
364         noAppsAlert.show();
365     }
366 }