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