Home | History | Annotate | Download | only in accessibility
      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      */
    219     public static boolean isColorTransformAccelerated(Context context) {
    220         return context.getResources()
    221                 .getBoolean(com.android.internal.R.bool.config_setColorTransformAccelerated);
    222     }
    223 
    224     @Override
    225     public int getMetricsCategory() {
    226         return MetricsEvent.ACCESSIBILITY;
    227     }
    228 
    229     @Override
    230     protected int getHelpResource() {
    231         return R.string.help_uri_accessibility;
    232     }
    233 
    234     @Override
    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
    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
    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
    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 
    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 
    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
    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 
    312     private void handleToggleTextContrastPreferenceClick() {
    313         Settings.Secure.putInt(getContentResolver(),
    314                 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
    315                 (mToggleHighTextContrastPreference.isChecked() ? 1 : 0));
    316     }
    317 
    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 
    326     private void handleLockScreenRotationPreferenceClick() {
    327         RotationPolicy.setRotationLockForAccessibility(getActivity(),
    328                 !mToggleLockScreenRotationPreference.isChecked());
    329     }
    330 
    331     private void handleToggleLargePointerIconPreferenceClick() {
    332         Settings.Secure.putInt(getContentResolver(),
    333                 Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
    334                 mToggleLargePointerIconPreference.isChecked() ? 1 : 0);
    335     }
    336 
    337     private void handleToggleMasterMonoPreferenceClick() {
    338         Settings.System.putIntForUser(getContentResolver(), Settings.System.MASTER_MONO,
    339                 mToggleMasterMonoPreference.isChecked() ? 1 : 0, UserHandle.USER_CURRENT);
    340     }
    341 
    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 
    418     private void updateAllPreferences() {
    419         updateSystemPreferences();
    420         updateServicePreferences();
    421     }
    422 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    681     private void updateLockScreenRotationCheckbox() {
    682         Context context = getActivity();
    683         if (context != null) {
    684             mToggleLockScreenRotationPreference.setChecked(
    685                     !RotationPolicy.isRotationLocked(context));
    686         }
    687     }
    688 
    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 
    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 
    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