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