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