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