OSDN Git Service

9b2c85327bbe5f50b3ab44df45127a3caac70aa8
[android-x86/packages-apps-Settings.git] / src / com / android / settings / accessibility / 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.accessibility;
18
19 import android.accessibilityservice.AccessibilityServiceInfo;
20 import android.app.Dialog;
21 import android.app.admin.DevicePolicyManager;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.DialogInterface;
25 import android.content.pm.PackageManager;
26 import android.content.pm.ServiceInfo;
27 import android.content.res.Resources;
28 import android.graphics.drawable.Drawable;
29 import android.net.Uri;
30 import android.os.Bundle;
31 import android.os.Handler;
32 import android.os.UserHandle;
33 import android.provider.SearchIndexableResource;
34 import android.provider.Settings;
35 import android.support.v14.preference.SwitchPreference;
36 import android.support.v7.preference.ListPreference;
37 import android.support.v7.preference.Preference;
38 import android.support.v7.preference.PreferenceCategory;
39 import android.support.v7.preference.PreferenceScreen;
40 import android.text.TextUtils;
41 import android.util.ArrayMap;
42 import android.view.KeyCharacterMap;
43 import android.view.KeyEvent;
44 import android.view.accessibility.AccessibilityManager;
45
46 import com.android.internal.content.PackageMonitor;
47 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
48 import com.android.internal.view.RotationPolicy;
49 import com.android.internal.view.RotationPolicy.RotationPolicyListener;
50 import com.android.settings.R;
51 import com.android.settings.SettingsPreferenceFragment;
52 import com.android.settings.Utils;
53 import com.android.settings.search.BaseSearchIndexProvider;
54 import com.android.settings.search.Indexable;
55 import com.android.settings.search.SearchIndexableRaw;
56 import com.android.settingslib.RestrictedLockUtils;
57 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
58 import com.android.settingslib.RestrictedPreference;
59 import com.android.settingslib.accessibility.AccessibilityUtils;
60
61 import java.util.ArrayList;
62 import java.util.HashMap;
63 import java.util.List;
64 import java.util.Map;
65 import java.util.Set;
66
67 /**
68  * Activity with the accessibility settings.
69  */
70 public class AccessibilitySettings extends SettingsPreferenceFragment implements
71         Preference.OnPreferenceChangeListener, Indexable {
72
73     // Index of the first preference in a preference category.
74     private static final int FIRST_PREFERENCE_IN_CATEGORY_INDEX = -1;
75
76     // Preference categories
77     private static final String CATEGORY_SCREEN_READER = "screen_reader_category";
78     private static final String CATEGORY_AUDIO_AND_CAPTIONS = "audio_and_captions_category";
79     private static final String CATEGORY_DISPLAY = "display_category";
80     private static final String CATEGORY_INTERACTION_CONTROL = "interaction_control_category";
81     private static final String CATEGORY_DOWNLOADED_SERVICES = "user_installed_services_category";
82
83     private static final String[] CATEGORIES = new String[] {
84         CATEGORY_SCREEN_READER, CATEGORY_AUDIO_AND_CAPTIONS, CATEGORY_DISPLAY,
85         CATEGORY_INTERACTION_CONTROL, CATEGORY_DOWNLOADED_SERVICES
86     };
87
88     // Preferences
89     private static final String TOGGLE_HIGH_TEXT_CONTRAST_PREFERENCE =
90             "toggle_high_text_contrast_preference";
91     private static final String TOGGLE_INVERSION_PREFERENCE =
92             "toggle_inversion_preference";
93     private static final String TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE =
94             "toggle_power_button_ends_call_preference";
95     private static final String TOGGLE_LOCK_SCREEN_ROTATION_PREFERENCE =
96             "toggle_lock_screen_rotation_preference";
97     private static final String TOGGLE_LARGE_POINTER_ICON =
98             "toggle_large_pointer_icon";
99     private static final String TOGGLE_MASTER_MONO =
100             "toggle_master_mono";
101     private static final String SELECT_LONG_PRESS_TIMEOUT_PREFERENCE =
102             "select_long_press_timeout_preference";
103     private static final String ACCESSIBILITY_SHORTCUT_PREFERENCE =
104             "accessibility_shortcut_preference";
105     private static final String CAPTIONING_PREFERENCE_SCREEN =
106             "captioning_preference_screen";
107     private static final String DISPLAY_MAGNIFICATION_PREFERENCE_SCREEN =
108             "screen_magnification_preference_screen";
109     private static final String FONT_SIZE_PREFERENCE_SCREEN =
110             "font_size_preference_screen";
111     private static final String AUTOCLICK_PREFERENCE_SCREEN =
112             "autoclick_preference_screen";
113     private static final String DISPLAY_DALTONIZER_PREFERENCE_SCREEN =
114             "daltonizer_preference_screen";
115
116     // Extras passed to sub-fragments.
117     static final String EXTRA_PREFERENCE_KEY = "preference_key";
118     static final String EXTRA_CHECKED = "checked";
119     static final String EXTRA_TITLE = "title";
120     static final String EXTRA_SUMMARY = "summary";
121     static final String EXTRA_SETTINGS_TITLE = "settings_title";
122     static final String EXTRA_COMPONENT_NAME = "component_name";
123     static final String EXTRA_SETTINGS_COMPONENT_NAME = "settings_component_name";
124     static final String EXTRA_VIDEO_RAW_RESOURCE_ID = "video_resource";
125     static final String EXTRA_LAUNCHED_FROM_SUW = "from_suw";
126
127     // Timeout before we update the services if packages are added/removed
128     // since the AccessibilityManagerService has to do that processing first
129     // to generate the AccessibilityServiceInfo we need for proper
130     // presentation.
131     private static final long DELAY_UPDATE_SERVICES_MILLIS = 1000;
132
133     // ID for dialog that confirms shortcut capabilities
134     private static final int DIALOG_ID_ADD_SHORTCUT_WARNING = 1;
135
136     private final Map<String, String> mLongPressTimeoutValueToTitleMap = new HashMap<>();
137
138     private final Handler mHandler = new Handler();
139
140     private final Runnable mUpdateRunnable = new Runnable() {
141         @Override
142         public void run() {
143             if (getActivity() != null) {
144                 updateServicePreferences();
145             }
146         }
147     };
148
149     private final PackageMonitor mSettingsPackageMonitor = new PackageMonitor() {
150         @Override
151         public void onPackageAdded(String packageName, int uid) {
152             sendUpdate();
153         }
154
155         @Override
156         public void onPackageAppeared(String packageName, int reason) {
157             sendUpdate();
158         }
159
160         @Override
161         public void onPackageDisappeared(String packageName, int reason) {
162             sendUpdate();
163         }
164
165         @Override
166         public void onPackageRemoved(String packageName, int uid) {
167             sendUpdate();
168         }
169
170         private void sendUpdate() {
171             mHandler.postDelayed(mUpdateRunnable, DELAY_UPDATE_SERVICES_MILLIS);
172         }
173     };
174
175     private final SettingsContentObserver mSettingsContentObserver =
176             new SettingsContentObserver(mHandler) {
177                 @Override
178                 public void onChange(boolean selfChange, Uri uri) {
179                     updateServicePreferences();
180                 }
181             };
182
183     private final RotationPolicyListener mRotationPolicyListener = new RotationPolicyListener() {
184         @Override
185         public void onChange() {
186             updateLockScreenRotationCheckbox();
187         }
188     };
189
190     private final Map<String, PreferenceCategory> mCategoryToPrefCategoryMap =
191             new ArrayMap<>();
192     private final Map<Preference, PreferenceCategory> mServicePreferenceToPreferenceCategoryMap =
193             new ArrayMap<>();
194     private final Map<ComponentName, PreferenceCategory> mPreBundledServiceComponentToCategoryMap =
195             new ArrayMap<>();
196
197     private SwitchPreference mToggleHighTextContrastPreference;
198     private SwitchPreference mTogglePowerButtonEndsCallPreference;
199     private SwitchPreference mToggleLockScreenRotationPreference;
200     private SwitchPreference mToggleLargePointerIconPreference;
201     private SwitchPreference mToggleMasterMonoPreference;
202     private ListPreference mSelectLongPressTimeoutPreference;
203     private Preference mNoServicesMessagePreference;
204     private Preference mCaptioningPreferenceScreen;
205     private Preference mDisplayMagnificationPreferenceScreen;
206     private Preference mFontSizePreferenceScreen;
207     private Preference mAutoclickPreferenceScreen;
208     private ListPreference mAccessibilityShortcutPreference;
209     private Preference mDisplayDaltonizerPreferenceScreen;
210     private SwitchPreference mToggleInversionPreference;
211
212     private int mLongPressTimeoutDefault;
213
214     private DevicePolicyManager mDpm;
215
216     @Override
217     public int getMetricsCategory() {
218         return MetricsEvent.ACCESSIBILITY;
219     }
220
221     @Override
222     protected int getHelpResource() {
223         return R.string.help_uri_accessibility;
224     }
225
226     @Override
227     public void onCreate(Bundle icicle) {
228         super.onCreate(icicle);
229         addPreferencesFromResource(R.xml.accessibility_settings);
230         initializeAllPreferences();
231         mDpm = (DevicePolicyManager) (getActivity()
232                 .getSystemService(Context.DEVICE_POLICY_SERVICE));
233     }
234
235     @Override
236     public void onResume() {
237         super.onResume();
238         updateAllPreferences();
239
240         mSettingsPackageMonitor.register(getActivity(), getActivity().getMainLooper(), false);
241         mSettingsContentObserver.register(getContentResolver());
242         if (RotationPolicy.isRotationSupported(getActivity())) {
243             RotationPolicy.registerRotationPolicyListener(getActivity(),
244                     mRotationPolicyListener);
245         }
246     }
247
248     @Override
249     public void onPause() {
250         mSettingsPackageMonitor.unregister();
251         mSettingsContentObserver.unregister(getContentResolver());
252         if (RotationPolicy.isRotationSupported(getActivity())) {
253             RotationPolicy.unregisterRotationPolicyListener(getActivity(),
254                     mRotationPolicyListener);
255         }
256         super.onPause();
257     }
258
259     @Override
260     public boolean onPreferenceChange(Preference preference, Object newValue) {
261         if (mSelectLongPressTimeoutPreference == preference) {
262             handleLongPressTimeoutPreferenceChange((String) newValue);
263             return true;
264         } else if (mToggleInversionPreference == preference) {
265             handleToggleInversionPreferenceChange((Boolean) newValue);
266             return true;
267         } else if (mAccessibilityShortcutPreference == preference) {
268             handleAccessibilityShortcutPreferenceChange((String) newValue);
269             return true;
270         }
271         return false;
272     }
273
274     private void handleLongPressTimeoutPreferenceChange(String stringValue) {
275         Settings.Secure.putInt(getContentResolver(),
276                 Settings.Secure.LONG_PRESS_TIMEOUT, Integer.parseInt(stringValue));
277         mSelectLongPressTimeoutPreference.setSummary(
278                 mLongPressTimeoutValueToTitleMap.get(stringValue));
279     }
280
281     private void handleToggleInversionPreferenceChange(boolean checked) {
282         Settings.Secure.putInt(getContentResolver(),
283                 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, (checked ? 1 : 0));
284     }
285
286     private void handleAccessibilityShortcutPreferenceChange(String serviceComponentName) {
287         // When assigning a service to the shortcut the user must explicitly agree to the same
288         // capabilities that are present if the service were being enabled.
289         // No need if clearing the setting or the service is already enabled.
290         if (TextUtils.isEmpty(serviceComponentName)
291                 || AccessibilityUtils.getEnabledServicesFromSettings(getActivity())
292                         .contains(ComponentName.unflattenFromString(serviceComponentName))) {
293             Settings.Secure.putString(getContentResolver(),
294                     Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, serviceComponentName);
295             updateAccessibilityShortcut();
296             return;
297         }
298         if (!serviceComponentName.equals(mAccessibilityShortcutPreference.getValue())) {
299             showDialog(DIALOG_ID_ADD_SHORTCUT_WARNING);
300         }
301     }
302
303     @Override
304     public Dialog onCreateDialog(int dialogId) {
305         switch (dialogId) {
306             case DIALOG_ID_ADD_SHORTCUT_WARNING: {
307                 DialogInterface.OnClickListener listener =
308                         (DialogInterface dialogInterface, int buttonId) -> {
309                             if (buttonId == DialogInterface.BUTTON_POSITIVE) {
310                                 Settings.Secure.putString(getContentResolver(),
311                                         Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
312                                         mAccessibilityShortcutPreference.getValue());
313                             }
314                             updateAccessibilityShortcut();
315                         };
316                 AccessibilityServiceInfo info = AccessibilityManager.getInstance(getActivity())
317                         .getInstalledServiceInfoWithComponentName(
318                                 ComponentName.unflattenFromString(
319                                         mAccessibilityShortcutPreference.getValue()));
320                 if (info == null) {
321                     return null;
322                 }
323                 return AccessibilityServiceWarning
324                         .createCapabilitiesDialog(getActivity(), info, listener);
325             }
326             default: {
327                 throw new IllegalArgumentException();
328             }
329         }
330     }
331
332     @Override
333     public int getDialogMetricsCategory(int dialogId) {
334         // The only dialog is the one that confirms the properties for the accessibility shortcut
335         return MetricsEvent.ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE;
336     }
337
338     @Override
339     public boolean onPreferenceTreeClick(Preference preference) {
340         if (mToggleHighTextContrastPreference == preference) {
341             handleToggleTextContrastPreferenceClick();
342             return true;
343         } else if (mTogglePowerButtonEndsCallPreference == preference) {
344             handleTogglePowerButtonEndsCallPreferenceClick();
345             return true;
346         } else if (mToggleLockScreenRotationPreference == preference) {
347             handleLockScreenRotationPreferenceClick();
348             return true;
349         } else if (mToggleLargePointerIconPreference == preference) {
350             handleToggleLargePointerIconPreferenceClick();
351             return true;
352         } else if (mToggleMasterMonoPreference == preference) {
353             handleToggleMasterMonoPreferenceClick();
354             return true;
355         }
356         return super.onPreferenceTreeClick(preference);
357     }
358
359     private void handleToggleTextContrastPreferenceClick() {
360         Settings.Secure.putInt(getContentResolver(),
361                 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
362                 (mToggleHighTextContrastPreference.isChecked() ? 1 : 0));
363     }
364
365     private void handleTogglePowerButtonEndsCallPreferenceClick() {
366         Settings.Secure.putInt(getContentResolver(),
367                 Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
368                 (mTogglePowerButtonEndsCallPreference.isChecked()
369                         ? Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP
370                         : Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF));
371     }
372
373     private void handleLockScreenRotationPreferenceClick() {
374         RotationPolicy.setRotationLockForAccessibility(getActivity(),
375                 !mToggleLockScreenRotationPreference.isChecked());
376     }
377
378     private void handleToggleLargePointerIconPreferenceClick() {
379         Settings.Secure.putInt(getContentResolver(),
380                 Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
381                 mToggleLargePointerIconPreference.isChecked() ? 1 : 0);
382     }
383
384     private void handleToggleMasterMonoPreferenceClick() {
385         Settings.System.putIntForUser(getContentResolver(), Settings.System.MASTER_MONO,
386                 mToggleMasterMonoPreference.isChecked() ? 1 : 0, UserHandle.USER_CURRENT);
387     }
388
389     private void initializeAllPreferences() {
390         for (int i = 0; i < CATEGORIES.length; i++) {
391             PreferenceCategory prefCategory = (PreferenceCategory) findPreference(CATEGORIES[i]);
392             mCategoryToPrefCategoryMap.put(CATEGORIES[i], prefCategory);
393         }
394
395         // Text contrast.
396         mToggleHighTextContrastPreference =
397                 (SwitchPreference) findPreference(TOGGLE_HIGH_TEXT_CONTRAST_PREFERENCE);
398
399         // Display inversion.
400         mToggleInversionPreference = (SwitchPreference) findPreference(TOGGLE_INVERSION_PREFERENCE);
401         mToggleInversionPreference.setOnPreferenceChangeListener(this);
402
403         // Power button ends calls.
404         mTogglePowerButtonEndsCallPreference =
405                 (SwitchPreference) findPreference(TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE);
406         if (!KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
407                 || !Utils.isVoiceCapable(getActivity())) {
408             mCategoryToPrefCategoryMap.get(CATEGORY_INTERACTION_CONTROL)
409                     .removePreference(mTogglePowerButtonEndsCallPreference);
410         }
411
412         // Lock screen rotation.
413         mToggleLockScreenRotationPreference =
414                 (SwitchPreference) findPreference(TOGGLE_LOCK_SCREEN_ROTATION_PREFERENCE);
415         if (!RotationPolicy.isRotationSupported(getActivity())) {
416             mCategoryToPrefCategoryMap.get(CATEGORY_INTERACTION_CONTROL)
417                     .removePreference(mToggleLockScreenRotationPreference);
418         }
419
420         // Large pointer icon.
421         mToggleLargePointerIconPreference =
422                 (SwitchPreference) findPreference(TOGGLE_LARGE_POINTER_ICON);
423
424         // Master Mono
425         mToggleMasterMonoPreference =
426                 (SwitchPreference) findPreference(TOGGLE_MASTER_MONO);
427
428         // Long press timeout.
429         mSelectLongPressTimeoutPreference =
430                 (ListPreference) findPreference(SELECT_LONG_PRESS_TIMEOUT_PREFERENCE);
431         mSelectLongPressTimeoutPreference.setOnPreferenceChangeListener(this);
432         if (mLongPressTimeoutValueToTitleMap.size() == 0) {
433             String[] timeoutValues = getResources().getStringArray(
434                     R.array.long_press_timeout_selector_values);
435             mLongPressTimeoutDefault = Integer.parseInt(timeoutValues[0]);
436             String[] timeoutTitles = getResources().getStringArray(
437                     R.array.long_press_timeout_selector_titles);
438             final int timeoutValueCount = timeoutValues.length;
439             for (int i = 0; i < timeoutValueCount; i++) {
440                 mLongPressTimeoutValueToTitleMap.put(timeoutValues[i], timeoutTitles[i]);
441             }
442         }
443
444         // Captioning.
445         mCaptioningPreferenceScreen = findPreference(CAPTIONING_PREFERENCE_SCREEN);
446
447         // Display magnification.
448         mDisplayMagnificationPreferenceScreen = findPreference(
449                 DISPLAY_MAGNIFICATION_PREFERENCE_SCREEN);
450
451         // Font size.
452         mFontSizePreferenceScreen = findPreference(FONT_SIZE_PREFERENCE_SCREEN);
453
454         // Autoclick after pointer stops.
455         mAutoclickPreferenceScreen = findPreference(AUTOCLICK_PREFERENCE_SCREEN);
456
457         // Display color adjustments.
458         mDisplayDaltonizerPreferenceScreen = findPreference(DISPLAY_DALTONIZER_PREFERENCE_SCREEN);
459
460         // Accessibility shortcut
461         mAccessibilityShortcutPreference =
462                 (ListPreference) findPreference(ACCESSIBILITY_SHORTCUT_PREFERENCE);
463         mAccessibilityShortcutPreference.setOnPreferenceChangeListener(this);
464     }
465
466     private void updateAllPreferences() {
467         updateSystemPreferences();
468         updateServicePreferences();
469     }
470
471     private void updateServicePreferences() {
472         // Since services category is auto generated we have to do a pass
473         // to generate it since services can come and go and then based on
474         // the global accessibility state to decided whether it is enabled.
475
476         // Generate.
477         ArrayList<Preference> servicePreferences =
478                 new ArrayList<>(mServicePreferenceToPreferenceCategoryMap.keySet());
479         for (int i = 0; i < servicePreferences.size(); i++) {
480             Preference service = servicePreferences.get(i);
481             PreferenceCategory category = mServicePreferenceToPreferenceCategoryMap.get(service);
482             category.removePreference(service);
483         }
484
485         initializePreBundledServicesMapFromArray(CATEGORY_SCREEN_READER,
486                 R.array.config_preinstalled_screen_reader_services);
487         initializePreBundledServicesMapFromArray(CATEGORY_AUDIO_AND_CAPTIONS,
488                 R.array.config_preinstalled_audio_and_caption_services);
489         initializePreBundledServicesMapFromArray(CATEGORY_DISPLAY,
490                 R.array.config_preinstalled_display_services);
491         initializePreBundledServicesMapFromArray(CATEGORY_INTERACTION_CONTROL,
492                 R.array.config_preinstalled_interaction_control_services);
493
494         AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(getActivity());
495
496         List<AccessibilityServiceInfo> installedServices =
497                 accessibilityManager.getInstalledAccessibilityServiceList();
498         Set<ComponentName> enabledServices = AccessibilityUtils.getEnabledServicesFromSettings(
499                 getActivity());
500         List<String> permittedServices = mDpm.getPermittedAccessibilityServices(
501                 UserHandle.myUserId());
502         final boolean accessibilityEnabled = Settings.Secure.getInt(getContentResolver(),
503                 Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
504
505         PreferenceCategory downloadedServicesCategory =
506                 mCategoryToPrefCategoryMap.get(CATEGORY_DOWNLOADED_SERVICES);
507         // Temporarily add the downloaded services category back if it was previously removed.
508         if (findPreference(CATEGORY_DOWNLOADED_SERVICES) == null) {
509             getPreferenceScreen().addPreference(downloadedServicesCategory);
510         }
511
512         for (int i = 0, count = installedServices.size(); i < count; ++i) {
513             AccessibilityServiceInfo info = installedServices.get(i);
514
515             RestrictedPreference preference =
516                     new RestrictedPreference(downloadedServicesCategory.getContext());
517             String title = info.getResolveInfo().loadLabel(getPackageManager()).toString();
518
519             Drawable icon = info.getResolveInfo().loadIcon(getPackageManager());
520             if (icon == null) {
521                 // todo (saigem): add a default
522             }
523
524             ServiceInfo serviceInfo = info.getResolveInfo().serviceInfo;
525             String packageName = serviceInfo.packageName;
526             ComponentName componentName = new ComponentName(packageName, serviceInfo.name);
527             String componentNameKey = componentName.flattenToString();
528
529             preference.setKey(componentName.flattenToString());
530
531             preference.setTitle(title);
532             preference.setIcon(icon);
533             final boolean serviceEnabled = accessibilityEnabled
534                     && enabledServices.contains(componentName);
535             String serviceState = serviceEnabled ?
536                     getString(R.string.accessibility_feature_state_on) :
537                     getString(R.string.accessibility_feature_state_off);
538             String serviceSummary = info.loadSummary(getPackageManager());
539             serviceSummary = (TextUtils.isEmpty(serviceSummary)) ? serviceState :
540                     serviceSummary;
541
542             // Disable all accessibility services that are not permitted.
543             boolean serviceAllowed =
544                     permittedServices == null || permittedServices.contains(packageName);
545             if (!serviceAllowed && !serviceEnabled) {
546                 EnforcedAdmin admin = RestrictedLockUtils.checkIfAccessibilityServiceDisallowed(
547                         getActivity(), packageName, UserHandle.myUserId());
548                 if (admin != null) {
549                     preference.setDisabledByAdmin(admin);
550                 } else {
551                     preference.setEnabled(false);
552                 }
553             } else {
554                 preference.setEnabled(true);
555             }
556
557             preference.setSummary(serviceSummary);
558             preference.setFragment(ToggleAccessibilityServicePreferenceFragment.class.getName());
559             preference.setPersistent(true);
560
561             Bundle extras = preference.getExtras();
562             extras.putString(EXTRA_PREFERENCE_KEY, preference.getKey());
563             extras.putBoolean(EXTRA_CHECKED, serviceEnabled);
564             extras.putString(EXTRA_TITLE, title);
565
566             String description = info.loadDescription(getPackageManager());
567             if (TextUtils.isEmpty(description)) {
568                 description = getString(R.string.accessibility_service_default_description);
569             }
570             extras.putString(EXTRA_SUMMARY, description);
571
572             String settingsClassName = info.getSettingsActivityName();
573             if (!TextUtils.isEmpty(settingsClassName)) {
574                 extras.putString(EXTRA_SETTINGS_TITLE,
575                         getString(R.string.accessibility_menu_item_settings));
576                 extras.putString(EXTRA_SETTINGS_COMPONENT_NAME,
577                         new ComponentName(packageName, settingsClassName).flattenToString());
578             }
579             extras.putParcelable(EXTRA_COMPONENT_NAME, componentName);
580
581             PreferenceCategory prefCategory = downloadedServicesCategory;
582             // Set the appropriate category if the service comes pre-installed.
583             if (mPreBundledServiceComponentToCategoryMap.containsKey(componentName)) {
584                 prefCategory = mPreBundledServiceComponentToCategoryMap.get(componentName);
585             }
586             preference.setOrder(FIRST_PREFERENCE_IN_CATEGORY_INDEX);
587             prefCategory.addPreference(preference);
588             mServicePreferenceToPreferenceCategoryMap.put(preference, prefCategory);
589         }
590
591         // If the user has not installed any additional services, hide the category.
592         if (downloadedServicesCategory.getPreferenceCount() == 0) {
593             PreferenceScreen screen = getPreferenceScreen();
594             screen.removePreference(downloadedServicesCategory);
595         }
596     }
597
598     private void initializePreBundledServicesMapFromArray(String categoryKey, int key) {
599         String[] services = getResources().getStringArray(key);
600         PreferenceCategory category = mCategoryToPrefCategoryMap.get(categoryKey);
601         for (int i = 0; i < services.length; i++) {
602             ComponentName component = ComponentName.unflattenFromString(services[i]);
603             mPreBundledServiceComponentToCategoryMap.put(component, category);
604         }
605     }
606
607     private void updateSystemPreferences() {
608         // Text contrast.
609         mToggleHighTextContrastPreference.setChecked(
610                 Settings.Secure.getInt(getContentResolver(),
611                         Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, 0) == 1);
612
613         // If the quick setting is enabled, the preference MUST be enabled.
614         mToggleInversionPreference.setChecked(Settings.Secure.getInt(getContentResolver(),
615                 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0) == 1);
616
617         // Power button ends calls.
618         if (KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
619                 && Utils.isVoiceCapable(getActivity())) {
620             final int incallPowerBehavior = Settings.Secure.getInt(getContentResolver(),
621                     Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
622                     Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT);
623             final boolean powerButtonEndsCall =
624                     (incallPowerBehavior == Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP);
625             mTogglePowerButtonEndsCallPreference.setChecked(powerButtonEndsCall);
626         }
627
628         // Auto-rotate screen
629         updateLockScreenRotationCheckbox();
630
631         // Large pointer icon.
632         mToggleLargePointerIconPreference.setChecked(Settings.Secure.getInt(getContentResolver(),
633                 Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON, 0) != 0);
634
635         // Master mono
636         updateMasterMono();
637
638         // Long press timeout.
639         final int longPressTimeout = Settings.Secure.getInt(getContentResolver(),
640                 Settings.Secure.LONG_PRESS_TIMEOUT, mLongPressTimeoutDefault);
641         String value = String.valueOf(longPressTimeout);
642         mSelectLongPressTimeoutPreference.setValue(value);
643         mSelectLongPressTimeoutPreference.setSummary(mLongPressTimeoutValueToTitleMap.get(value));
644
645         updateFeatureSummary(Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED,
646                 mCaptioningPreferenceScreen);
647         updateFeatureSummary(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
648                 mDisplayDaltonizerPreferenceScreen);
649
650         updateFontSizeSummary(mFontSizePreferenceScreen);
651
652         updateAutoclickSummary(mAutoclickPreferenceScreen);
653
654         updateAccessibilityShortcut();
655     }
656
657     private void updateFeatureSummary(String prefKey, Preference pref) {
658         final boolean enabled = Settings.Secure.getInt(getContentResolver(), prefKey, 0) == 1;
659         pref.setSummary(enabled ? R.string.accessibility_feature_state_on
660                 : R.string.accessibility_feature_state_off);
661     }
662
663     private void updateAutoclickSummary(Preference pref) {
664         final boolean enabled = Settings.Secure.getInt(
665                 getContentResolver(), Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED, 0) == 1;
666         if (!enabled) {
667             pref.setSummary(R.string.accessibility_feature_state_off);
668             return;
669         }
670         int delay = Settings.Secure.getInt(
671                 getContentResolver(), Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY,
672                 AccessibilityManager.AUTOCLICK_DELAY_DEFAULT);
673         pref.setSummary(ToggleAutoclickPreferenceFragment.getAutoclickPreferenceSummary(
674                 getResources(), delay));
675     }
676
677     private void updateFontSizeSummary(Preference pref) {
678         final float currentScale = Settings.System.getFloat(getContext().getContentResolver(),
679                 Settings.System.FONT_SCALE, 1.0f);
680         final Resources res = getContext().getResources();
681         final String[] entries = res.getStringArray(R.array.entries_font_size);
682         final String[] strEntryValues = res.getStringArray(R.array.entryvalues_font_size);
683         final int index = ToggleFontSizePreferenceFragment.fontSizeValueToIndex(currentScale,
684                 strEntryValues);
685         pref.setSummary(entries[index]);
686     }
687
688     private void updateLockScreenRotationCheckbox() {
689         Context context = getActivity();
690         if (context != null) {
691             mToggleLockScreenRotationPreference.setChecked(
692                     !RotationPolicy.isRotationLocked(context));
693         }
694     }
695
696     private void updateMasterMono() {
697         final boolean masterMono = Settings.System.getIntForUser(
698                 getContentResolver(), Settings.System.MASTER_MONO,
699                 0 /* default */, UserHandle.USER_CURRENT) == 1;
700         mToggleMasterMonoPreference.setChecked(masterMono);
701     }
702
703     private void updateAccessibilityShortcut() {
704         String currentShortcutNameString =
705                 AccessibilityUtils.getShortcutTargetServiceComponentNameString(getActivity(),
706                         UserHandle.myUserId());
707         final PackageManager pm = getPackageManager();
708         final AccessibilityManager accessibilityManager = getActivity()
709                 .getSystemService(AccessibilityManager.class);
710         final List<AccessibilityServiceInfo> installedServices =
711                 accessibilityManager.getInstalledAccessibilityServiceList();
712         final int numInstalledServices = installedServices.size();
713
714         CharSequence[] entries = new CharSequence[numInstalledServices + 1];
715         CharSequence[] entryValues = new CharSequence[numInstalledServices + 1];
716         int currentSettingIndex = numInstalledServices;
717         for (int i = 0; i < numInstalledServices; i++) {
718             AccessibilityServiceInfo installedService = installedServices.get(i);
719             entries[i] = installedService.getResolveInfo().loadLabel(pm);
720             entryValues[i] = installedService.getComponentName().flattenToShortString();
721             if (installedService.getId().equals(currentShortcutNameString)) {
722                 currentSettingIndex = i;
723             }
724         }
725         entries[numInstalledServices] =
726                 getString(com.android.internal.R.string.disable_accessibility_shortcut);
727         entryValues[numInstalledServices] = "";
728         mAccessibilityShortcutPreference.setEntryValues(entryValues);
729         mAccessibilityShortcutPreference.setEntries(entries);
730         mAccessibilityShortcutPreference.setSummary(entries[currentSettingIndex]);
731         mAccessibilityShortcutPreference.setValueIndex(currentSettingIndex);
732     }
733
734     public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
735             new BaseSearchIndexProvider() {
736         @Override
737         public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
738             List<SearchIndexableRaw> indexables = new ArrayList<SearchIndexableRaw>();
739
740             PackageManager packageManager = context.getPackageManager();
741             AccessibilityManager accessibilityManager =
742                     context.getSystemService(AccessibilityManager.class);
743
744             String screenTitle = context.getResources().getString(
745                     R.string.accessibility_settings);
746
747             // Indexing all services, regardless if enabled.
748             List<AccessibilityServiceInfo> services = accessibilityManager
749                     .getInstalledAccessibilityServiceList();
750             final int serviceCount = services.size();
751             for (int i = 0; i < serviceCount; i++) {
752                 AccessibilityServiceInfo service = services.get(i);
753                 if (service == null || service.getResolveInfo() == null) {
754                     continue;
755                 }
756
757                 ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
758                 ComponentName componentName = new ComponentName(serviceInfo.packageName,
759                         serviceInfo.name);
760
761                 SearchIndexableRaw indexable = new SearchIndexableRaw(context);
762                 indexable.key = componentName.flattenToString();
763                 indexable.title = service.getResolveInfo().loadLabel(packageManager).toString();
764                 indexable.screenTitle = screenTitle;
765                 indexables.add(indexable);
766             }
767
768             return indexables;
769         }
770
771         @Override
772         public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
773                boolean enabled) {
774             List<SearchIndexableResource> indexables = new ArrayList<>();
775             SearchIndexableResource indexable = new SearchIndexableResource(context);
776             indexable.xmlResId = R.xml.accessibility_settings;
777             indexables.add(indexable);
778             return indexables;
779         }
780     };
781 }