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.accessibility;
18 
19 import android.accessibilityservice.AccessibilityServiceInfo;
20 import android.app.ActivityManagerNative;
21 import android.app.admin.DevicePolicyManager;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.pm.PackageManager;
25 import android.content.pm.ResolveInfo;
26 import android.content.pm.ServiceInfo;
27 import android.content.res.Configuration;
28 import android.net.Uri;
29 import android.os.Bundle;
30 import android.os.Handler;
31 import android.os.RemoteException;
32 import android.os.UserHandle;
33 import android.preference.ListPreference;
34 import android.preference.Preference;
35 import android.preference.PreferenceCategory;
36 import android.preference.PreferenceScreen;
37 import android.preference.SwitchPreference;
38 import android.provider.SearchIndexableResource;
39 import android.provider.Settings;
40 import android.text.TextUtils;
41 import android.text.TextUtils.SimpleStringSplitter;
42 import android.view.KeyCharacterMap;
43 import android.view.KeyEvent;
44 import android.view.View;
45 import android.view.accessibility.AccessibilityManager;
46 import android.widget.TextView;
47 
48 import com.android.internal.content.PackageMonitor;
49 import com.android.internal.view.RotationPolicy;
50 import com.android.internal.view.RotationPolicy.RotationPolicyListener;
51 import com.android.settings.DialogCreatable;
52 import com.android.settings.R;
53 import com.android.settings.SettingsPreferenceFragment;
54 import com.android.settings.Utils;
55 import com.android.settings.search.BaseSearchIndexProvider;
56 import com.android.settings.search.Indexable;
57 import com.android.settings.search.SearchIndexableRaw;
58 
59 import java.util.ArrayList;
60 import java.util.HashMap;
61 import java.util.HashSet;
62 import java.util.List;
63 import java.util.Map;
64 import java.util.Set;
65 
66 /**
67  * Activity with the accessibility settings.
68  */
69 public class AccessibilitySettings extends SettingsPreferenceFragment implements DialogCreatable,
70         Preference.OnPreferenceChangeListener, Indexable {
71 
72     private static final float LARGE_FONT_SCALE = 1.3f;
73 
74     static final char ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR = ':';
75 
76     // Preference categories
77     private static final String SERVICES_CATEGORY = "services_category";
78     private static final String SYSTEM_CATEGORY = "system_category";
79 
80     // Preferences
81     private static final String TOGGLE_LARGE_TEXT_PREFERENCE =
82             "toggle_large_text_preference";
83     private static final String TOGGLE_HIGH_TEXT_CONTRAST_PREFERENCE =
84             "toggle_high_text_contrast_preference";
85     private static final String TOGGLE_INVERSION_PREFERENCE =
86             "toggle_inversion_preference";
87     private static final String TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE =
88             "toggle_power_button_ends_call_preference";
89     private static final String TOGGLE_LOCK_SCREEN_ROTATION_PREFERENCE =
90             "toggle_lock_screen_rotation_preference";
91     private static final String TOGGLE_SPEAK_PASSWORD_PREFERENCE =
92             "toggle_speak_password_preference";
93     private static final String SELECT_LONG_PRESS_TIMEOUT_PREFERENCE =
94             "select_long_press_timeout_preference";
95     private static final String ENABLE_ACCESSIBILITY_GESTURE_PREFERENCE_SCREEN =
96             "enable_global_gesture_preference_screen";
97     private static final String CAPTIONING_PREFERENCE_SCREEN =
98             "captioning_preference_screen";
99     private static final String DISPLAY_MAGNIFICATION_PREFERENCE_SCREEN =
100             "screen_magnification_preference_screen";
101     private static final String DISPLAY_DALTONIZER_PREFERENCE_SCREEN =
102             "daltonizer_preference_screen";
103 
104     // Extras passed to sub-fragments.
105     static final String EXTRA_PREFERENCE_KEY = "preference_key";
106     static final String EXTRA_CHECKED = "checked";
107     static final String EXTRA_TITLE = "title";
108     static final String EXTRA_SUMMARY = "summary";
109     static final String EXTRA_SETTINGS_TITLE = "settings_title";
110     static final String EXTRA_COMPONENT_NAME = "component_name";
111     static final String EXTRA_SETTINGS_COMPONENT_NAME = "settings_component_name";
112 
113     // Timeout before we update the services if packages are added/removed
114     // since the AccessibilityManagerService has to do that processing first
115     // to generate the AccessibilityServiceInfo we need for proper
116     // presentation.
117     private static final long DELAY_UPDATE_SERVICES_MILLIS = 1000;
118 
119     // Auxiliary members.
120     final static SimpleStringSplitter sStringColonSplitter =
121             new SimpleStringSplitter(ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR);
122 
123     static final Set<ComponentName> sInstalledServices = new HashSet<ComponentName>();
124 
125     private final Map<String, String> mLongPressTimeoutValuetoTitleMap =
126             new HashMap<String, String>();
127 
128     private final Configuration mCurConfig = new Configuration();
129 
130     private final Handler mHandler = new Handler();
131 
132     private final Runnable mUpdateRunnable = new Runnable() {
133         @Override
134         public void run() {
135             loadInstalledServices();
136             updateServicesPreferences();
137         }
138     };
139 
140     private final PackageMonitor mSettingsPackageMonitor = new PackageMonitor() {
141         @Override
142         public void onPackageAdded(String packageName, int uid) {
143             sendUpdate();
144         }
145 
146         @Override
147         public void onPackageAppeared(String packageName, int reason) {
148             sendUpdate();
149         }
150 
151         @Override
152         public void onPackageDisappeared(String packageName, int reason) {
153             sendUpdate();
154         }
155 
156         @Override
157         public void onPackageRemoved(String packageName, int uid) {
158             sendUpdate();
159         }
160 
161         private void sendUpdate() {
162             mHandler.postDelayed(mUpdateRunnable, DELAY_UPDATE_SERVICES_MILLIS);
163         }
164     };
165 
166     private final SettingsContentObserver mSettingsContentObserver =
167             new SettingsContentObserver(mHandler) {
168                 @Override
169                 public void onChange(boolean selfChange, Uri uri) {
170                     loadInstalledServices();
171                     updateServicesPreferences();
172                 }
173             };
174 
175     private final RotationPolicyListener mRotationPolicyListener = new RotationPolicyListener() {
176         @Override
177         public void onChange() {
178             updateLockScreenRotationCheckbox();
179         }
180     };
181 
182     // Preference controls.
183     private PreferenceCategory mServicesCategory;
184     private PreferenceCategory mSystemsCategory;
185 
186     private SwitchPreference mToggleLargeTextPreference;
187     private SwitchPreference mToggleHighTextContrastPreference;
188     private SwitchPreference mTogglePowerButtonEndsCallPreference;
189     private SwitchPreference mToggleLockScreenRotationPreference;
190     private SwitchPreference mToggleSpeakPasswordPreference;
191     private ListPreference mSelectLongPressTimeoutPreference;
192     private Preference mNoServicesMessagePreference;
193     private PreferenceScreen mCaptioningPreferenceScreen;
194     private PreferenceScreen mDisplayMagnificationPreferenceScreen;
195     private PreferenceScreen mGlobalGesturePreferenceScreen;
196     private PreferenceScreen mDisplayDaltonizerPreferenceScreen;
197     private SwitchPreference mToggleInversionPreference;
198 
199     private int mLongPressTimeoutDefault;
200 
201     private DevicePolicyManager mDpm;
202 
203     @Override
onCreate(Bundle icicle)204     public void onCreate(Bundle icicle) {
205         super.onCreate(icicle);
206         addPreferencesFromResource(R.xml.accessibility_settings);
207         initializeAllPreferences();
208         mDpm = (DevicePolicyManager) (getActivity()
209                 .getSystemService(Context.DEVICE_POLICY_SERVICE));
210     }
211 
212     @Override
onResume()213     public void onResume() {
214         super.onResume();
215         loadInstalledServices();
216         updateAllPreferences();
217 
218         mSettingsPackageMonitor.register(getActivity(), getActivity().getMainLooper(), false);
219         mSettingsContentObserver.register(getContentResolver());
220         if (RotationPolicy.isRotationSupported(getActivity())) {
221             RotationPolicy.registerRotationPolicyListener(getActivity(),
222                     mRotationPolicyListener);
223         }
224     }
225 
226     @Override
onPause()227     public void onPause() {
228         mSettingsPackageMonitor.unregister();
229         mSettingsContentObserver.unregister(getContentResolver());
230         if (RotationPolicy.isRotationSupported(getActivity())) {
231             RotationPolicy.unregisterRotationPolicyListener(getActivity(),
232                     mRotationPolicyListener);
233         }
234         super.onPause();
235     }
236 
237     @Override
onPreferenceChange(Preference preference, Object newValue)238     public boolean onPreferenceChange(Preference preference, Object newValue) {
239         if (mSelectLongPressTimeoutPreference == preference) {
240             handleLongPressTimeoutPreferenceChange((String) newValue);
241             return true;
242         } else if (mToggleInversionPreference == preference) {
243             handleToggleInversionPreferenceChange((Boolean) newValue);
244             return true;
245         }
246         return false;
247     }
248 
handleLongPressTimeoutPreferenceChange(String stringValue)249     private void handleLongPressTimeoutPreferenceChange(String stringValue) {
250         Settings.Secure.putInt(getContentResolver(),
251                 Settings.Secure.LONG_PRESS_TIMEOUT, Integer.parseInt(stringValue));
252         mSelectLongPressTimeoutPreference.setSummary(
253                 mLongPressTimeoutValuetoTitleMap.get(stringValue));
254     }
255 
handleToggleInversionPreferenceChange(boolean checked)256     private void handleToggleInversionPreferenceChange(boolean checked) {
257         Settings.Secure.putInt(getContentResolver(),
258                 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, (checked ? 1 : 0));
259     }
260 
261     @Override
onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)262     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
263         if (mToggleLargeTextPreference == preference) {
264             handleToggleLargeTextPreferenceClick();
265             return true;
266         } else if (mToggleHighTextContrastPreference == preference) {
267             handleToggleTextContrastPreferenceClick();
268             return true;
269         } else if (mTogglePowerButtonEndsCallPreference == preference) {
270             handleTogglePowerButtonEndsCallPreferenceClick();
271             return true;
272         } else if (mToggleLockScreenRotationPreference == preference) {
273             handleLockScreenRotationPreferenceClick();
274             return true;
275         } else if (mToggleSpeakPasswordPreference == preference) {
276             handleToggleSpeakPasswordPreferenceClick();
277             return true;
278         } else if (mGlobalGesturePreferenceScreen == preference) {
279             handleToggleEnableAccessibilityGesturePreferenceClick();
280             return true;
281         } else if (mDisplayMagnificationPreferenceScreen == preference) {
282             handleDisplayMagnificationPreferenceScreenClick();
283             return true;
284         }
285         return super.onPreferenceTreeClick(preferenceScreen, preference);
286     }
287 
handleToggleLargeTextPreferenceClick()288     private void handleToggleLargeTextPreferenceClick() {
289         try {
290             mCurConfig.fontScale = mToggleLargeTextPreference.isChecked() ? LARGE_FONT_SCALE : 1;
291             ActivityManagerNative.getDefault().updatePersistentConfiguration(mCurConfig);
292         } catch (RemoteException re) {
293             /* ignore */
294         }
295     }
296 
handleToggleTextContrastPreferenceClick()297     private void handleToggleTextContrastPreferenceClick() {
298         Settings.Secure.putInt(getContentResolver(),
299                 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
300                 (mToggleHighTextContrastPreference.isChecked() ? 1 : 0));
301     }
302 
handleTogglePowerButtonEndsCallPreferenceClick()303     private void handleTogglePowerButtonEndsCallPreferenceClick() {
304         Settings.Secure.putInt(getContentResolver(),
305                 Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
306                 (mTogglePowerButtonEndsCallPreference.isChecked()
307                         ? Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP
308                         : Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF));
309     }
310 
handleLockScreenRotationPreferenceClick()311     private void handleLockScreenRotationPreferenceClick() {
312         RotationPolicy.setRotationLockForAccessibility(getActivity(),
313                 !mToggleLockScreenRotationPreference.isChecked());
314     }
315 
handleToggleSpeakPasswordPreferenceClick()316     private void handleToggleSpeakPasswordPreferenceClick() {
317         Settings.Secure.putInt(getContentResolver(),
318                 Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD,
319                 mToggleSpeakPasswordPreference.isChecked() ? 1 : 0);
320     }
321 
handleToggleEnableAccessibilityGesturePreferenceClick()322     private void handleToggleEnableAccessibilityGesturePreferenceClick() {
323         Bundle extras = mGlobalGesturePreferenceScreen.getExtras();
324         extras.putString(EXTRA_TITLE, getString(
325                 R.string.accessibility_global_gesture_preference_title));
326         extras.putString(EXTRA_SUMMARY, getString(
327                 R.string.accessibility_global_gesture_preference_description));
328         extras.putBoolean(EXTRA_CHECKED, Settings.Global.getInt(getContentResolver(),
329                 Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1);
330         super.onPreferenceTreeClick(mGlobalGesturePreferenceScreen,
331                 mGlobalGesturePreferenceScreen);
332     }
333 
handleDisplayMagnificationPreferenceScreenClick()334     private void handleDisplayMagnificationPreferenceScreenClick() {
335         Bundle extras = mDisplayMagnificationPreferenceScreen.getExtras();
336         extras.putString(EXTRA_TITLE, getString(
337                 R.string.accessibility_screen_magnification_title));
338         extras.putCharSequence(EXTRA_SUMMARY, getActivity().getResources().getText(
339                 R.string.accessibility_screen_magnification_summary));
340         extras.putBoolean(EXTRA_CHECKED, Settings.Secure.getInt(getContentResolver(),
341                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 0) == 1);
342         super.onPreferenceTreeClick(mDisplayMagnificationPreferenceScreen,
343                 mDisplayMagnificationPreferenceScreen);
344     }
345 
initializeAllPreferences()346     private void initializeAllPreferences() {
347         mServicesCategory = (PreferenceCategory) findPreference(SERVICES_CATEGORY);
348         mSystemsCategory = (PreferenceCategory) findPreference(SYSTEM_CATEGORY);
349 
350         // Large text.
351         mToggleLargeTextPreference =
352                 (SwitchPreference) findPreference(TOGGLE_LARGE_TEXT_PREFERENCE);
353 
354         // Text contrast.
355         mToggleHighTextContrastPreference =
356                 (SwitchPreference) findPreference(TOGGLE_HIGH_TEXT_CONTRAST_PREFERENCE);
357 
358         // Display inversion.
359         mToggleInversionPreference = (SwitchPreference) findPreference(TOGGLE_INVERSION_PREFERENCE);
360         mToggleInversionPreference.setOnPreferenceChangeListener(this);
361 
362         // Power button ends calls.
363         mTogglePowerButtonEndsCallPreference =
364                 (SwitchPreference) findPreference(TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE);
365         if (!KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
366                 || !Utils.isVoiceCapable(getActivity())) {
367             mSystemsCategory.removePreference(mTogglePowerButtonEndsCallPreference);
368         }
369 
370         // Lock screen rotation.
371         mToggleLockScreenRotationPreference =
372                 (SwitchPreference) findPreference(TOGGLE_LOCK_SCREEN_ROTATION_PREFERENCE);
373         if (!RotationPolicy.isRotationSupported(getActivity())) {
374             mSystemsCategory.removePreference(mToggleLockScreenRotationPreference);
375         }
376 
377         // Speak passwords.
378         mToggleSpeakPasswordPreference =
379                 (SwitchPreference) findPreference(TOGGLE_SPEAK_PASSWORD_PREFERENCE);
380 
381         // Long press timeout.
382         mSelectLongPressTimeoutPreference =
383                 (ListPreference) findPreference(SELECT_LONG_PRESS_TIMEOUT_PREFERENCE);
384         mSelectLongPressTimeoutPreference.setOnPreferenceChangeListener(this);
385         if (mLongPressTimeoutValuetoTitleMap.size() == 0) {
386             String[] timeoutValues = getResources().getStringArray(
387                     R.array.long_press_timeout_selector_values);
388             mLongPressTimeoutDefault = Integer.parseInt(timeoutValues[0]);
389             String[] timeoutTitles = getResources().getStringArray(
390                     R.array.long_press_timeout_selector_titles);
391             final int timeoutValueCount = timeoutValues.length;
392             for (int i = 0; i < timeoutValueCount; i++) {
393                 mLongPressTimeoutValuetoTitleMap.put(timeoutValues[i], timeoutTitles[i]);
394             }
395         }
396 
397         // Captioning.
398         mCaptioningPreferenceScreen = (PreferenceScreen) findPreference(
399                 CAPTIONING_PREFERENCE_SCREEN);
400 
401         // Display magnification.
402         mDisplayMagnificationPreferenceScreen = (PreferenceScreen) findPreference(
403                 DISPLAY_MAGNIFICATION_PREFERENCE_SCREEN);
404 
405         // Display color adjustments.
406         mDisplayDaltonizerPreferenceScreen = (PreferenceScreen) findPreference(
407                 DISPLAY_DALTONIZER_PREFERENCE_SCREEN);
408 
409         // Global gesture.
410         mGlobalGesturePreferenceScreen =
411                 (PreferenceScreen) findPreference(ENABLE_ACCESSIBILITY_GESTURE_PREFERENCE_SCREEN);
412         final int longPressOnPowerBehavior = getActivity().getResources().getInteger(
413                 com.android.internal.R.integer.config_longPressOnPowerBehavior);
414         final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
415         if (!KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
416                 || longPressOnPowerBehavior != LONG_PRESS_POWER_GLOBAL_ACTIONS) {
417             // Remove accessibility shortcut if power key is not present
418             // nor long press power does not show global actions menu.
419             mSystemsCategory.removePreference(mGlobalGesturePreferenceScreen);
420         }
421     }
422 
updateAllPreferences()423     private void updateAllPreferences() {
424         updateServicesPreferences();
425         updateSystemPreferences();
426     }
427 
updateServicesPreferences()428     private void updateServicesPreferences() {
429         // Since services category is auto generated we have to do a pass
430         // to generate it since services can come and go and then based on
431         // the global accessibility state to decided whether it is enabled.
432 
433         // Generate.
434         mServicesCategory.removeAll();
435 
436         AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(getActivity());
437 
438         List<AccessibilityServiceInfo> installedServices =
439                 accessibilityManager.getInstalledAccessibilityServiceList();
440         Set<ComponentName> enabledServices = AccessibilityUtils.getEnabledServicesFromSettings(
441                 getActivity());
442         List<String> permittedServices = mDpm.getPermittedAccessibilityServices(
443                 UserHandle.myUserId());
444         final boolean accessibilityEnabled = Settings.Secure.getInt(getContentResolver(),
445                 Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
446 
447         for (int i = 0, count = installedServices.size(); i < count; ++i) {
448             AccessibilityServiceInfo info = installedServices.get(i);
449 
450             PreferenceScreen preference = getPreferenceManager().createPreferenceScreen(
451                     getActivity());
452             String title = info.getResolveInfo().loadLabel(getPackageManager()).toString();
453 
454             ServiceInfo serviceInfo = info.getResolveInfo().serviceInfo;
455             ComponentName componentName = new ComponentName(serviceInfo.packageName,
456                     serviceInfo.name);
457 
458             preference.setKey(componentName.flattenToString());
459 
460             preference.setTitle(title);
461             final boolean serviceEnabled = accessibilityEnabled
462                     && enabledServices.contains(componentName);
463             String serviceEnabledString;
464             if (serviceEnabled) {
465                 serviceEnabledString = getString(R.string.accessibility_feature_state_on);
466             } else {
467                 serviceEnabledString = getString(R.string.accessibility_feature_state_off);
468             }
469 
470             // Disable all accessibility services that are not permitted.
471             String packageName = serviceInfo.packageName;
472             boolean serviceAllowed =
473                     permittedServices == null || permittedServices.contains(packageName);
474             preference.setEnabled(serviceAllowed || serviceEnabled);
475 
476             String summaryString;
477             if (serviceAllowed) {
478                 summaryString = serviceEnabledString;
479             } else  {
480                 summaryString = getString(R.string.accessibility_feature_or_input_method_not_allowed);
481             }
482             preference.setSummary(summaryString);
483 
484             preference.setOrder(i);
485             preference.setFragment(ToggleAccessibilityServicePreferenceFragment.class.getName());
486             preference.setPersistent(true);
487 
488             Bundle extras = preference.getExtras();
489             extras.putString(EXTRA_PREFERENCE_KEY, preference.getKey());
490             extras.putBoolean(EXTRA_CHECKED, serviceEnabled);
491             extras.putString(EXTRA_TITLE, title);
492 
493             String description = info.loadDescription(getPackageManager());
494             if (TextUtils.isEmpty(description)) {
495                 description = getString(R.string.accessibility_service_default_description);
496             }
497             extras.putString(EXTRA_SUMMARY, description);
498 
499             String settingsClassName = info.getSettingsActivityName();
500             if (!TextUtils.isEmpty(settingsClassName)) {
501                 extras.putString(EXTRA_SETTINGS_TITLE,
502                         getString(R.string.accessibility_menu_item_settings));
503                 extras.putString(EXTRA_SETTINGS_COMPONENT_NAME,
504                         new ComponentName(info.getResolveInfo().serviceInfo.packageName,
505                                 settingsClassName).flattenToString());
506             }
507 
508             extras.putParcelable(EXTRA_COMPONENT_NAME, componentName);
509 
510             mServicesCategory.addPreference(preference);
511         }
512 
513         if (mServicesCategory.getPreferenceCount() == 0) {
514             if (mNoServicesMessagePreference == null) {
515                 mNoServicesMessagePreference = new Preference(getActivity());
516                 mNoServicesMessagePreference.setPersistent(false);
517                 mNoServicesMessagePreference.setLayoutResource(
518                         R.layout.text_description_preference);
519                 mNoServicesMessagePreference.setSelectable(false);
520                 mNoServicesMessagePreference.setSummary(
521                         getString(R.string.accessibility_no_services_installed));
522             }
523             mServicesCategory.addPreference(mNoServicesMessagePreference);
524         }
525     }
526 
updateSystemPreferences()527     private void updateSystemPreferences() {
528         // Large text.
529         try {
530             mCurConfig.updateFrom(ActivityManagerNative.getDefault().getConfiguration());
531         } catch (RemoteException re) {
532             /* ignore */
533         }
534         mToggleLargeTextPreference.setChecked(mCurConfig.fontScale == LARGE_FONT_SCALE);
535 
536         mToggleHighTextContrastPreference.setChecked(
537                 Settings.Secure.getInt(getContentResolver(),
538                         Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, 0) == 1);
539 
540         // If the quick setting is enabled, the preference MUST be enabled.
541         mToggleInversionPreference.setChecked(Settings.Secure.getInt(getContentResolver(),
542                 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0) == 1);
543 
544         // Power button ends calls.
545         if (KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
546                 && Utils.isVoiceCapable(getActivity())) {
547             final int incallPowerBehavior = Settings.Secure.getInt(getContentResolver(),
548                     Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
549                     Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT);
550             final boolean powerButtonEndsCall =
551                     (incallPowerBehavior == Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP);
552             mTogglePowerButtonEndsCallPreference.setChecked(powerButtonEndsCall);
553         }
554 
555         // Auto-rotate screen
556         updateLockScreenRotationCheckbox();
557 
558         // Speak passwords.
559         final boolean speakPasswordEnabled = Settings.Secure.getInt(getContentResolver(),
560                 Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0) != 0;
561         mToggleSpeakPasswordPreference.setChecked(speakPasswordEnabled);
562 
563         // Long press timeout.
564         final int longPressTimeout = Settings.Secure.getInt(getContentResolver(),
565                 Settings.Secure.LONG_PRESS_TIMEOUT, mLongPressTimeoutDefault);
566         String value = String.valueOf(longPressTimeout);
567         mSelectLongPressTimeoutPreference.setValue(value);
568         mSelectLongPressTimeoutPreference.setSummary(mLongPressTimeoutValuetoTitleMap.get(value));
569 
570         updateFeatureSummary(Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED,
571                 mCaptioningPreferenceScreen);
572         updateFeatureSummary(Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
573                 mDisplayMagnificationPreferenceScreen);
574         updateFeatureSummary(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
575                 mDisplayDaltonizerPreferenceScreen);
576 
577         // Global gesture
578         final boolean globalGestureEnabled = Settings.Global.getInt(getContentResolver(),
579                 Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1;
580         if (globalGestureEnabled) {
581             mGlobalGesturePreferenceScreen.setSummary(
582                     R.string.accessibility_global_gesture_preference_summary_on);
583         } else {
584             mGlobalGesturePreferenceScreen.setSummary(
585                     R.string.accessibility_global_gesture_preference_summary_off);
586         }
587     }
588 
updateFeatureSummary(String prefKey, Preference pref)589     private void updateFeatureSummary(String prefKey, Preference pref) {
590         final boolean enabled = Settings.Secure.getInt(getContentResolver(), prefKey, 0) == 1;
591         pref.setSummary(enabled ? R.string.accessibility_feature_state_on
592                 : R.string.accessibility_feature_state_off);
593     }
594 
updateLockScreenRotationCheckbox()595     private void updateLockScreenRotationCheckbox() {
596         Context context = getActivity();
597         if (context != null) {
598             mToggleLockScreenRotationPreference.setChecked(
599                     !RotationPolicy.isRotationLocked(context));
600         }
601     }
602 
loadInstalledServices()603     private void loadInstalledServices() {
604         Set<ComponentName> installedServices = sInstalledServices;
605         installedServices.clear();
606 
607         List<AccessibilityServiceInfo> installedServiceInfos =
608                 AccessibilityManager.getInstance(getActivity())
609                         .getInstalledAccessibilityServiceList();
610         if (installedServiceInfos == null) {
611             return;
612         }
613 
614         final int installedServiceInfoCount = installedServiceInfos.size();
615         for (int i = 0; i < installedServiceInfoCount; i++) {
616             ResolveInfo resolveInfo = installedServiceInfos.get(i).getResolveInfo();
617             ComponentName installedService = new ComponentName(
618                     resolveInfo.serviceInfo.packageName,
619                     resolveInfo.serviceInfo.name);
620             installedServices.add(installedService);
621         }
622     }
623 
624     public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
625             new BaseSearchIndexProvider() {
626         @Override
627         public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
628             List<SearchIndexableRaw> indexables = new ArrayList<SearchIndexableRaw>();
629 
630             PackageManager packageManager = context.getPackageManager();
631             AccessibilityManager accessibilityManager = (AccessibilityManager)
632                     context.getSystemService(Context.ACCESSIBILITY_SERVICE);
633 
634             String screenTitle = context.getResources().getString(
635                     R.string.accessibility_services_title);
636 
637             // Indexing all services, regardless if enabled.
638             List<AccessibilityServiceInfo> services = accessibilityManager
639                     .getInstalledAccessibilityServiceList();
640             final int serviceCount = services.size();
641             for (int i = 0; i < serviceCount; i++) {
642                 AccessibilityServiceInfo service = services.get(i);
643                 if (service == null || service.getResolveInfo() == null) {
644                     continue;
645                 }
646 
647                 ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
648                 ComponentName componentName = new ComponentName(serviceInfo.packageName,
649                         serviceInfo.name);
650 
651                 SearchIndexableRaw indexable = new SearchIndexableRaw(context);
652                 indexable.key = componentName.flattenToString();
653                 indexable.title = service.getResolveInfo().loadLabel(packageManager).toString();
654                 indexable.summaryOn = context.getString(R.string.accessibility_feature_state_on);
655                 indexable.summaryOff = context.getString(R.string.accessibility_feature_state_off);
656                 indexable.screenTitle = screenTitle;
657                 indexables.add(indexable);
658             }
659 
660             return indexables;
661         }
662 
663         @Override
664         public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
665                boolean enabled) {
666             List<SearchIndexableResource> indexables = new ArrayList<SearchIndexableResource>();
667             SearchIndexableResource indexable = new SearchIndexableResource(context);
668             indexable.xmlResId = R.xml.accessibility_settings;
669             indexables.add(indexable);
670             return indexables;
671         }
672     };
673 }
674