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