Revamp of the accessibility settings.

1. Reimplemented accessibility settings accrding to UX design.

NOTE: The strings are not final, rather reasonable placeholders
   to avoid blocking on them. Will submit another CL with string
   updates and any necessary polishes.

bug:5065409

Change-Id: I3ba229a624298dbf238bc8562b42616b386f8c34
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 858aa2a..962c985 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -691,12 +691,15 @@
         </activity>
 
         <activity android:name="Settings$AccessibilitySettingsActivity"
-                android:label="@string/accessibility_settings_title">
+                android:label="@string/accessibility_settings_title"
+                android:configChanges="orientation|keyboardHidden|screenSize"
+                android:clearTaskOnLaunch="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <action android:name="android.settings.ACCESSIBILITY_SETTINGS" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.VOICE_LAUNCH" />
+                <category android:name="com.android.settings.SHORTCUT" />
             </intent-filter>
             <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
                 android:value="com.android.settings.AccessibilitySettings" />
diff --git a/res/layout/text_description_preference.xml b/res/layout/text_description_preference.xml
new file mode 100644
index 0000000..c5084034
--- /dev/null
+++ b/res/layout/text_description_preference.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical" >
+
+    <TextView
+        android:id="@+id/summary"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:textColor="?android:attr/textColorSecondary"
+        android:padding="16dip" />
+
+</LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b28ba93..56498e4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2659,78 +2659,73 @@
     <string name="accessibility_settings">Accessibility</string>
     <!-- Settings title for accessibility settings screen -->
     <string name="accessibility_settings_title">Accessibility settings</string>
-    <!-- Settings summary for accessibility settings [CHAR LIMIT=40] -->
-    <string name="accessibility_settings_summary">Manage accessibility options</string>
-    <!-- Setting Checkbox title for enabling accessibility large text [CHAR LIMIT=25] -->
-    <string name="toggle_large_text_title">Large text</string>
-    <!-- Setting accessibility services category [CHAR LIMIT=25] -->
-    <string name="accessibility_services_category">Accessibility services</string>
-    <!-- Setting Checkbox title for enabling accessibility services [CHAR LIMIT=40] -->
-    <string name="toggle_accessibility_title">Allow accessibility services</string>
-    <!-- Setting Checkbox title for enabling touch exploration mode [CHAR LIMIT=40] -->
-    <string name="accessibility_touch_exploration_title">Enable touch exploration mode</string>
-    <!-- Setting Checkbox summary for enabling touch exploration mode [CHAR LIMIT=65] -->
-    <string name="accessibility_touch_exploration_summary">Allows you to touch the screen to hear the contents under your finger.</string>
-    <!-- Warning message describing changes in interaction from enabling touch exploration mode
-         and suggesting that the user goes through a tutorial, displayed as a dialog message the
-         first time the user selects to enable touch exploration -->
-    <string name="accessibility_touch_exploration_warning">Touch exploration mode changes the way your
-        device handles touch input. Would you like to take a short tutorial on using touch exploration?</string>
-    <!-- Message for announcing the lack of installed accessibility services. -->
-    <string name="no_accessibility_services_summary">No installed accessibility services.</string>
+
+    <!--  Title for the accessibility preference category of accessibility services. [CHAR LIMIT=25] -->
+    <string name="accessibility_services_title">Services</string>
+
+    <!-- Title for the accessibility preference category of system related preferences. [CHAR LIMIT=25] -->
+    <string name="accessibility_system_title">System</string>
+    <!-- Title for the accessibility preference to enable large text. [CHAR LIMIT=35] -->
+    <string name="accessibility_toggle_large_text_title">Large text</string>
+    <!-- Title for the accessibility preference to power button to end a call. [CHAR LIMIT=35] -->
+    <string name="accessibility_power_button_ends_call_title">Power button ends call</string>
+    <!-- Title for accessibility preference to enable touch exploration mode. [CHAR LIMIT=35] -->
+    <string name="accessibility_touch_exploration_title">Explore by touch</string>
+    <!-- Summary for accessibility of the touch exploration mode. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_touch_exploration_summary" >Allows exploring screen content and interacting with the device.\n\n
+        Touch the screen to receive feedback of the content under your finger.\n\n Tap on the last explored location to activate.\n\n
+        Use two fingers to drag. </string>
+    <!-- Title for accessibility preference to choose long-press delay i.e. timeout before it is detected. [CHAR LIMIT=35] -->
+    <string name="accessibility_long_press_timeout_title">Touch &amp; hold delay</string>
+    <!-- Title for accessibility preference to install accessibility scripts from Google. [CHAR LIMIT=35] -->
+    <string name="accessibility_script_injection_title">Install accessibility scripts</string>
+
+    <!-- Title for accessibility menu item to lauch a settings activity. [CHAR LIMIT=15] -->
+    <string name="accessibility_menu_item_settings">Settings</string>
+    <!-- Title for accessibility menu item to lauch a tutorial. [CHAR LIMIT=15] -->
+    <string name="accessibility_menu_item_tutorial">Tutorial</string>
+
+    <!-- Summary for the enabled state of an accessiblity serivce. [CHAR LIMIT=10] -->
+    <string name="accessibility_service_state_on">On</string>
+    <!-- Summary for the disabled state of an accessiblity serivce. [CHAR LIMIT=10] -->
+    <string name="accessibility_service_state_off">Off</string>
+
+    <!-- Summary for the allowed state of script injection. [CHAR LIMIT=15] -->
+    <string name="accessibility_script_injection_allowed">Allowed</string>
+    <!-- Summary for the disallowed state of script injection. [CHAR LIMIT=15] -->
+    <string name="accessibility_script_injection_disallowed">Disallowed</string>
+
+    <!-- Title for the dialog button to allow script injection. [CHAR LIMIT=15] -->
+    <string name="accessibility_script_injection_button_allow">Allow</string>
+    <!-- Title for the dialog button to disallow script injection. [CHAR LIMIT=15] -->
+    <string name="accessibility_script_injection_button_disallow">Don\'t Allow</string>
+
     <!-- Warning message about security implications of enabling an accessibility service,
-         displayed as a dialog message when the user selects to enable an accessibility service. -->
+         displayed as a dialog message when the user selects to enable an accessibility service. [CHAR LIMIT=NONE] -->
     <string name="accessibility_service_security_warning">This accessibility service may be able to collect
         all the text you type, including personal data credit card numbers except passwords.
         It may also log your user interface interactions. It comes from the application
         <xliff:g id="accessibility_service_name">%1$s</xliff:g>. Use this accessibility service?</string>
     <!-- Warning about disabling accessibility displayed as a dialog message when the user
-         selects to disable accessibility. This avoids accidental disabling. -->
+         selects to disable accessibility. This avoids accidental disabling. [CHAR LIMIT=NONE] -->
     <string name="accessibility_service_disable_warning">Disable accessibility?</string>
     <!-- Title for the prompt that lets users know that they have no accessibility related apps
-         installed and that they can install TalkBack from Market. -->
+         installed and that they can install TalkBack from Market. [CHAR LIMIT=50] -->
     <string name="accessibility_service_no_apps_title">No accessibility related applications found
         </string>
     <!-- Message for the prompt that lets users know that they have no accessibility related apps
-         installed and that they can install TalkBack from Market. -->
+         installed and that they can install TalkBack from Market. [CHAR LIMIT=NONE] -->
     <string name="accessibility_service_no_apps_message">You do not have any accessibility-related
         applications installed.\n\nYou can download a screen reader for your device from Android
         Market.\n\nClick "OK" to install the screen reader.</string>
-
-    <!-- Accessibility settings: Checkbox title for enabling download of accessibility scripts [CHAR LIMIT=40] -->
-    <string name="accessibility_script_injection_enabled">Download accessibility scripts</string>
-    <!-- Accessibility settings: Checkbox summary for enabling download of accessibility scripts [CHAR LIMIT=65] -->
-    <string name="accessibility_script_injection_enabled_summary">Allow applications to download accessibility scripts from Google</string>
     <!-- Warning message about security implications of downloading accessibility scripts,
-         displayed as a dialog message when the user selects to enable script downloading. [CHAR LIMIT="NONE"] -->
-    <string name="accessibility_script_injection_security_warning" product="tablet">Some applications can ask Google
-        to download scripts to your tablet that make their content more accessible. Are you sure you
-        want to allow Google to install accessibility scripts on your tablet?</string>
-    <!-- Warning message about security implications of downloading accessibility scripts,
-         displayed as a dialog message when the user selects to enable script downloading. [CHAR LIMIT="NONE"] -->
-    <string name="accessibility_script_injection_security_warning" product="default">Some applications can ask Google
-        to download scripts to your phone that make their content more accessible. Are you sure you
-        want to allow Google to install accessibility scripts on your phone?</string>
-    <!-- Accessibility settings: Power button category -->
-    <string name="accessibility_power_button_category">Power button</string>
-    <!-- Accessibility settings: checkbox title for power button behavior -->
-    <string name="accessibility_power_button_ends_call">Power button ends call</string>
-    <!-- Accessibility settings: power button behavior summary text -->
-    <string name="accessibility_power_button_ends_call_summary">During a call, pressing Power ends call instead of turning off screen</string>
-    <!-- Accessibility settings: touch exploration state -->
-    <string name="accessibility_touch_exploration_enabled">Touch exploration</string>
-
-    <!-- Accessibility settings: button for lauching settings for an accessibility service -->
-    <string name="settings_button">Settings</string>
-
-    <!-- Setting interaction category [CHAR LIMIT=35] -->
-    <string name="touchscreen_gestures_category">Touchscreen gestures</string>
-    <!-- Title for setting the long-press timeout [CHAR LIMIT=35] -->
-    <string name="long_press_timeout_selector_title">Touch &amp; hold delay</string>
-    <!-- Summary for setting the long-press timeout [CHAR LIMIT=85] -->
-    <string name="long_press_timeout_selector_summary">Delay until a touch is interpreted as a touch &amp; hold</string>
-    <!-- The default value for the long press timeout. -->
-    <string name="long_press_timeout_selector_default_value" translatable="false">500</string>
+         displayed as a dialog message when the user selects to enable script downloading. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_script_injection_security_warning">Some applications can ask Google
+        to download scripts to your device that make their content more accessible. Are you sure you
+        want to allow Google to install accessibility scripts on your device?</string>
+    <!-- Warning message that the interaction model changes on enabling touch exploration. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_touch_exploration_warning">Enabling explore by touch
+        changes the interation model. Enable explore by touch?</string>
 
     <!-- App Fuel Gauge strings -->
     <skip />
diff --git a/res/values/styles.xml b/res/values/styles.xml
index b832e97..ffa7912 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -159,7 +159,7 @@
         <item name="android:widgetLayout">@layout/preference_inputmethod_widget</item>
     </style>
 
-    <style name="AcessibilityTutorialButton">
+    <style name="AccessibilityTutorialButton">
         <item name="android:layout_width">150dip</item>
         <item name="android:layout_height">wrap_content</item>
         <item name="android:layout_margin">5dip</item>
diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml
index feb5fb1..78a857b 100644
--- a/res/xml/accessibility_settings.xml
+++ b/res/xml/accessibility_settings.xml
@@ -18,48 +18,48 @@
         xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
         android:title="@string/accessibility_settings_title">
 
-    <CheckBoxPreference
-            android:key="toggle_large_text_checkbox"
-            android:title="@string/toggle_large_text_title"
-            android:persistent="false"/>
-
-    <PreferenceCategory android:key="accessibility_services_category"
-            android:title="@string/accessibility_services_category">
-        <CheckBoxPreference
-                android:key="toggle_accessibility_service_checkbox"
-                android:title="@string/toggle_accessibility_title"
-                android:persistent="false"
-                android:order="-10000"/>
-        <CheckBoxPreference
-                android:key="toggle_accessibility_script_injection_checkbox"
-                android:title="@string/accessibility_script_injection_enabled"
-                android:summary="@string/accessibility_script_injection_enabled_summary"
-                android:persistent="false"
-                android:order="10000" />
+    <PreferenceCategory
+            android:key="services_category"
+            android:title="@string/accessibility_services_title">
     </PreferenceCategory>
 
-    <PreferenceCategory android:key="power_button_category"
-            android:title="@string/accessibility_power_button_category">
-        <CheckBoxPreference
-                android:key="power_button_ends_call"
-                android:title="@string/accessibility_power_button_ends_call"
-                android:summary="@string/accessibility_power_button_ends_call_summary"
-                android:persistent="false" />
-    </PreferenceCategory>
+    <PreferenceCategory
+            android:key="system_category"
+            android:title="@string/accessibility_system_title">
 
-    <PreferenceCategory android:key="touchscreen_gestures_category"
-            android:title="@string/touchscreen_gestures_category">
-        <ListPreference android:key="long_press_timeout_list_preference"
-                android:title="@string/long_press_timeout_selector_title"
-                android:summary="@string/long_press_timeout_selector_summary"
-                android:persistent="true"
+        <CheckBoxPreference
+                android:key="toggle_large_text_preference"
+                android:title="@string/accessibility_toggle_large_text_title"
+                android:persistent="false"/>
+
+        <CheckBoxPreference
+                android:key="toggle_power_button_ends_call_preference"
+                android:title="@string/accessibility_power_button_ends_call_title"
+                android:persistent="false">
+        </CheckBoxPreference>
+
+        <PreferenceScreen
+                android:key="toggle_touch_exploration_preference"
+                android:title="@string/accessibility_touch_exploration_title"
+                android:fragment="com.android.settings.AccessibilitySettings$ToggleTouchExplorationFragment" >
+                <extra android:name="title" android:value="@string/accessibility_touch_exploration_title" />
+                <extra android:name="summary" android:value="@string/accessibility_touch_exploration_summary" />
+                <extra android:name="warning_message" android:value="@string/accessibility_touch_exploration_warning" />
+                <extra android:name="settings_title" android:value="@string/accessibility_menu_item_tutorial" />
+                <extra android:name="settings_component_name" android:value="com.android.settings/com.android.settings.AccessibilityTutorialActivity" />
+        </PreferenceScreen>
+
+        <ListPreference android:key="select_long_press_timeout_preference"
+                android:title="@string/accessibility_long_press_timeout_title"
                 android:entries="@array/long_press_timeout_selector_titles"
                 android:entryValues="@array/long_press_timeout_selector_values"
-                android:defaultValue="@string/long_press_timeout_selector_default_value"/>
-        <CheckBoxPreference
-                android:key="touch_exploration_enabled"
-                android:title="@string/accessibility_touch_exploration_enabled"
+                android:persistent="true" />
+
+        <Preference
+                android:key="toggle_script_injection_preference"
+                android:title="@string/accessibility_script_injection_title"
                 android:persistent="false" />
+
     </PreferenceCategory>
 
 </PreferenceScreen>
diff --git a/src/com/android/settings/AccessibilitySettings.java b/src/com/android/settings/AccessibilitySettings.java
index 578268d..beef902 100644
--- a/src/com/android/settings/AccessibilitySettings.java
+++ b/src/com/android/settings/AccessibilitySettings.java
@@ -17,34 +17,50 @@
 package com.android.settings;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.ActionBar;
+import android.app.Activity;
 import android.app.ActivityManagerNative;
 import android.app.AlertDialog;
 import android.app.Dialog;
-import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.pm.ServiceInfo;
 import android.content.res.Configuration;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.preference.CheckBoxPreference;
 import android.preference.ListPreference;
 import android.preference.Preference;
 import android.preference.PreferenceCategory;
-import android.preference.PreferenceGroup;
 import android.preference.PreferenceScreen;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.text.TextUtils.SimpleStringSplitter;
+import android.view.Gravity;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
 import android.view.accessibility.AccessibilityManager;
+import android.widget.Switch;
+import android.widget.TextView;
 
+import com.android.internal.content.PackageMonitor;
+import com.android.settings.AccessibilitySettings.ToggleSwitch.OnBeforeCheckedChangeListener;
+
+import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Activity with the accessibility settings.
@@ -57,392 +73,335 @@
 
     private static final float LARGE_FONT_SCALE = 1.3f;
 
-    private static final String TOGGLE_LARGE_TEXT_CHECKBOX =
-        "toggle_large_text_checkbox";
+    // Timeout before we update the services if packages are added/removed since
+    // the AccessibilityManagerService has to do that processing first to generate
+    // the AccessibilityServiceInfo we need for proper presentation.
+    private static final long DELAY_UPDATE_SERVICES_PREFERENCES_MILLIS = 1000;
 
-    private static final String TOGGLE_ACCESSIBILITY_CHECKBOX =
-        "toggle_accessibility_service_checkbox";
+    private static final char ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR = ':';
 
-    private static final String ACCESSIBILITY_SERVICES_CATEGORY =
-        "accessibility_services_category";
+    // Preference categories
+    private static final String SERVICES_CATEGORY = "services_category";
 
-    private static final String TOGGLE_ACCESSIBILITY_SCRIPT_INJECTION_CHECKBOX =
-        "toggle_accessibility_script_injection_checkbox";
+    // Preferences
+    private static final String TOGGLE_LARGE_TEXT_PREFERENCE = "toggle_large_text_preference";
+    private static final String TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE =
+        "toggle_power_button_ends_call_preference";
+    private static final String TOGGLE_TOUCH_EXPLORATION_PREFERENCE =
+        "toggle_touch_exploration_preference";
+    private static final String SELECT_LONG_PRESS_TIMEOUT_PREFERENCE =
+        "select_long_press_timeout_preference";
+    private static final String TOGGLE_SCRIPT_INJECTION_PREFERENCE =
+        "toggle_script_injection_preference";
 
-    private static final String POWER_BUTTON_CATEGORY =
-        "power_button_category";
+    // Extras passed to sub-fragments.
+    static final String EXTRA_PREFERENCE_KEY = "preference_key";
+    static final String EXTRA_CHECKED = "checked";
+    static final String EXTRA_TITLE = "title";
+    static final String EXTRA_SUMMARY = "summary";
+    static final String EXTRA_WARNING_MESSAGE = "warning_message";
+    static final String EXTRA_SETTINGS_TITLE = "settings_title";
+    static final String EXTRA_SETTINGS_COMPONENT_NAME = "settings_component_name";
 
-    private static final String POWER_BUTTON_ENDS_CALL_CHECKBOX =
-        "power_button_ends_call";
-
-    private static final String TOUCH_EXPLORATION_ENABLED_CHECKBOX =
-        "touch_exploration_enabled";
-
-    private static final String KEY_TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX =
-        "key_toggle_accessibility_service_checkbox";
-
-    private static final String KEY_LONG_PRESS_TIMEOUT_LIST_PREFERENCE =
-        "long_press_timeout_list_preference";
-
+    // Dialog IDs.
     private static final int DIALOG_ID_DISABLE_ACCESSIBILITY = 1;
     private static final int DIALOG_ID_ENABLE_SCRIPT_INJECTION = 2;
-    private static final int DIALOG_ID_ENABLE_ACCESSIBILITY_SERVICE = 3;
-    private static final int DIALOG_ID_NO_ACCESSIBILITY_SERVICES = 4;
+    private static final int DIALOG_ID_NO_ACCESSIBILITY_SERVICES = 3;
 
-    private CheckBoxPreference mToggleLargeTextCheckBox;
-    private CheckBoxPreference mToggleAccessibilityCheckBox;
-    private CheckBoxPreference mToggleScriptInjectionCheckBox;
-    private SettingsCheckBoxPreference mToggleAccessibilityServiceCheckBox;
+    // Auxiliary members.
+    private final SimpleStringSplitter mStringColonSplitter =
+        new SimpleStringSplitter(ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR);
 
-    private PreferenceCategory mPowerButtonCategory;
-    private CheckBoxPreference mPowerButtonEndsCallCheckBox;
-    private CheckBoxPreference mTouchExplorationEnabledCheckBox;
-
-    private PreferenceGroup mAccessibilityServicesCategory;
-
-    private ListPreference mLongPressTimeoutListPreference;
+    private final Map<String, String> mLongPressTimeoutValuetoTitleMap =
+        new HashMap<String, String>();
 
     private final Configuration mCurConfig = new Configuration();
 
-    private Map<String, AccessibilityServiceInfo> mAccessibilityServices =
-        new LinkedHashMap<String, AccessibilityServiceInfo>();
+    private final PackageMonitor mSettingsPackageMonitor = new SettingsPackageMonitor();
 
-    private TextUtils.SimpleStringSplitter mStringColonSplitter =
-        new TextUtils.SimpleStringSplitter(':');
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void dispatchMessage(Message msg) {
+            super.dispatchMessage(msg);
+            updateServicesPreferences();
+        }
+    };
+
+    // Preference controls.
+    private ToggleSwitch mToggleAccessibilitySwitch;
+
+    private PreferenceCategory mServicesCategory;
+
+    private CheckBoxPreference mToggleLargeTextPreference;
+    private CheckBoxPreference mTogglePowerButtonEndsCallPreference;
+    private Preference mTouchExplorationEnabledPreference;
+    private ListPreference mSelectLongPressTimeoutPreference;
+    private Preference mToggleScriptInjectionPreference;
 
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
-
         addPreferencesFromResource(R.xml.accessibility_settings);
-
-        mToggleLargeTextCheckBox = (CheckBoxPreference) findPreference(
-                TOGGLE_LARGE_TEXT_CHECKBOX);
-
-        mAccessibilityServicesCategory =
-            (PreferenceGroup) findPreference(ACCESSIBILITY_SERVICES_CATEGORY);
-
-        mToggleAccessibilityCheckBox = (CheckBoxPreference) findPreference(
-                TOGGLE_ACCESSIBILITY_CHECKBOX);
-
-        mToggleScriptInjectionCheckBox = (CheckBoxPreference) findPreference(
-                TOGGLE_ACCESSIBILITY_SCRIPT_INJECTION_CHECKBOX);
-
-        mPowerButtonCategory = (PreferenceCategory) findPreference(POWER_BUTTON_CATEGORY);
-        mPowerButtonEndsCallCheckBox = (CheckBoxPreference) findPreference(
-                POWER_BUTTON_ENDS_CALL_CHECKBOX);
-
-        mTouchExplorationEnabledCheckBox = (CheckBoxPreference) findPreference(
-                TOUCH_EXPLORATION_ENABLED_CHECKBOX);
-
-        mLongPressTimeoutListPreference = (ListPreference) findPreference(
-                KEY_LONG_PRESS_TIMEOUT_LIST_PREFERENCE);
-
-        // set the accessibility script injection category
-        boolean scriptInjectionEnabled = (Settings.Secure.getInt(getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0) == 1);
-        mToggleScriptInjectionCheckBox.setChecked(scriptInjectionEnabled);
-        mToggleScriptInjectionCheckBox.setEnabled(true);
-
-        if (KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
-                && Utils.isVoiceCapable(getActivity())) {
-            int incallPowerBehavior = Settings.Secure.getInt(getContentResolver(),
-                    Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
-                    Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT);
-            // The checkbox is labeled "Power button ends call"; thus the in-call
-            // Power button behavior is INCALL_POWER_BUTTON_BEHAVIOR_HANGUP if
-            // checked, and INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF if unchecked.
-            boolean powerButtonCheckboxEnabled =
-                    (incallPowerBehavior == Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP);
-            mPowerButtonEndsCallCheckBox.setChecked(powerButtonCheckboxEnabled);
-            mPowerButtonEndsCallCheckBox.setEnabled(true);
-        } else {
-            // No POWER key on the current device or no voice capability;
-            // this entire category is irrelevant.
-            getPreferenceScreen().removePreference(mPowerButtonCategory);
-        }
-
-        boolean touchExplorationEnabled = (Settings.Secure.getInt(getContentResolver(),
-                Settings.Secure.TOUCH_EXPLORATION_REQUESTED, 0) == 1);
-        mTouchExplorationEnabledCheckBox.setChecked(touchExplorationEnabled);
-
-        mLongPressTimeoutListPreference.setOnPreferenceChangeListener(this);
+        installToggleAccessibilitySwitch();
+        findPreferences();
     }
 
     @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
-        addAccessibilityServicePreferences();
-
-        final HashSet<String> enabled = new HashSet<String>();
-        String settingValue = Settings.Secure.getString(getContentResolver(),
-                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
-        if (settingValue != null) {
-            TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
-            splitter.setString(settingValue);
-            while (splitter.hasNext()) {
-                enabled.add(splitter.next());
-            }
-        }
-
-        Map<String, AccessibilityServiceInfo> accessibilityServices = mAccessibilityServices;
-
-        for (String key : accessibilityServices.keySet()) {
-            CheckBoxPreference preference = (CheckBoxPreference) findPreference(key);
-            if (preference != null) {
-                preference.setChecked(enabled.contains(key));
-            }
-        }
-
-        int serviceState = Settings.Secure.getInt(getContentResolver(),
-            Settings.Secure.ACCESSIBILITY_ENABLED, 0);
-
-        if (!accessibilityServices.isEmpty()) {
-            if (serviceState == 1) {
-                mToggleAccessibilityCheckBox.setChecked(true);
-                if (savedInstanceState != null) {
-                    restoreInstanceState(savedInstanceState);
-                }
-            } else {
-                setAccessibilityServicePreferencesState(false);
-            }
-            mToggleAccessibilityCheckBox.setEnabled(true);
-        } else {
-            if (serviceState == 1) {
-                // no service and accessibility is enabled => disable
-                Settings.Secure.putInt(getContentResolver(),
-                    Settings.Secure.ACCESSIBILITY_ENABLED, 0);
-            }
-            mToggleAccessibilityCheckBox.setEnabled(false);
-            // Notify user that they do not have any accessibility apps
-            // installed and direct them to Market to get TalkBack
-            showDialog(DIALOG_ID_NO_ACCESSIBILITY_SERVICES);
-        }
-
-        readFontSizePreference();
-
-        super.onActivityCreated(savedInstanceState);
+    public void onResume() {
+        super.onResume();
+        updateServicesPreferences();
+        updateSystemPreferences();
+        updatePreferencesForAccessibilityState();
+        mSettingsPackageMonitor.register(getActivity(), false);
     }
 
     @Override
     public void onPause() {
         super.onPause();
-
-        persistEnabledAccessibilityServices();
-    }
-
-    @Override
-    public void onSaveInstanceState(Bundle outState) {
-        if (mToggleAccessibilityServiceCheckBox != null) {
-            outState.putString(KEY_TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX,
-                    mToggleAccessibilityServiceCheckBox.getKey());
-        }
+        mSettingsPackageMonitor.unregister();
     }
 
     public boolean onPreferenceChange(Preference preference, Object newValue) {
-        if (preference == mLongPressTimeoutListPreference) {
-            int intValue = Integer.parseInt((String) newValue);
+        if (preference == mSelectLongPressTimeoutPreference) {
+            final int intValue = Integer.parseInt((String) newValue);
             Settings.Secure.putInt(getContentResolver(),
-                Settings.Secure.LONG_PRESS_TIMEOUT, intValue);
+                    Settings.Secure.LONG_PRESS_TIMEOUT, intValue);
+            mSelectLongPressTimeoutPreference.setSummary(
+                    mLongPressTimeoutValuetoTitleMap.get(String.valueOf(intValue)));
             return true;
         }
         return false;
     }
 
-    /**
-     * Restores the instance state from <code>savedInstanceState</code>.
-     */
-    private void restoreInstanceState(Bundle savedInstanceState) {
-        String key = savedInstanceState.getString(KEY_TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX);
-        if (key != null) {
-            Preference preference = findPreference(key);
-            if (!(preference instanceof CheckBoxPreference)) {
-                throw new IllegalArgumentException(
-                        KEY_TOGGLE_ACCESSIBILITY_SERVICE_CHECKBOX
-                                + " must be mapped to an instance of a "
-                                + SettingsCheckBoxPreference.class.getName());
-            }
-            mToggleAccessibilityServiceCheckBox = (SettingsCheckBoxPreference) preference;
-        }
-    }
-
-    /**
-     * Sets the state of the preferences for enabling/disabling
-     * AccessibilityServices.
-     *
-     * @param isEnabled If to enable or disable the preferences.
-     */
-    private void setAccessibilityServicePreferencesState(boolean isEnabled) {
-        if (mAccessibilityServicesCategory == null) {
-            return;
-        }
-
-        int count = mAccessibilityServicesCategory.getPreferenceCount();
-        for (int i = 0; i < count; i++) {
-            Preference pref = mAccessibilityServicesCategory.getPreference(i);
-            if (pref != mToggleAccessibilityCheckBox) {
-                pref.setEnabled(isEnabled);
-            }
-        }
+    private void updatePreferencesForAccessibilityState() {
+        final boolean accessibilityEnabled = (Settings.Secure.getInt(getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1);
+        mServicesCategory.setEnabled(accessibilityEnabled);
+        mTouchExplorationEnabledPreference.setEnabled(accessibilityEnabled);
+        mToggleScriptInjectionPreference.setEnabled(accessibilityEnabled);
     }
 
     @Override
     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
         final String key = preference.getKey();
-
-        if (TOGGLE_ACCESSIBILITY_CHECKBOX.equals(key)) {
-            handleEnableAccessibilityStateChange((CheckBoxPreference) preference);
-        } else if (TOGGLE_LARGE_TEXT_CHECKBOX.equals(key)) {
-            try {
-                mCurConfig.fontScale = mToggleLargeTextCheckBox.isChecked()
-                        ? LARGE_FONT_SCALE : 1;
-                ActivityManagerNative.getDefault().updatePersistentConfiguration(mCurConfig);
-            } catch (RemoteException e) {
-            }
-        } else if (POWER_BUTTON_ENDS_CALL_CHECKBOX.equals(key)) {
-            boolean isChecked = ((CheckBoxPreference) preference).isChecked();
-            // The checkbox is labeled "Power button ends call"; thus the in-call
-            // Power button behavior is INCALL_POWER_BUTTON_BEHAVIOR_HANGUP if
-            // checked, and INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF if unchecked.
-            Settings.Secure.putInt(getContentResolver(),
-                    Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
-                    (isChecked ? Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP
-                            : Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF));
-        } else if (TOUCH_EXPLORATION_ENABLED_CHECKBOX.equals(key)) {
-            final int touchExplorationState = ((CheckBoxPreference) preference).isChecked() ? 1 : 0;
-            Settings.Secure.putInt(getContentResolver(),
-                    Settings.Secure.TOUCH_EXPLORATION_REQUESTED, touchExplorationState);
-        } else if (TOGGLE_ACCESSIBILITY_SCRIPT_INJECTION_CHECKBOX.equals(key)) {
-            handleToggleAccessibilityScriptInjection((CheckBoxPreference) preference);
-        } else if (preference instanceof CheckBoxPreference) {
-            handleEnableAccessibilityServiceStateChange((SettingsCheckBoxPreference) preference);
+        if (mToggleLargeTextPreference == preference) {
+            handleToggleLargeTextPreference((CheckBoxPreference) preference);
+            return true;
+        } else if (mTogglePowerButtonEndsCallPreference == preference) {
+            handleTogglePowerButtonEndsCallPreference((CheckBoxPreference) preference);
+            return true;
+        } else if (mToggleScriptInjectionPreference == preference) {
+            handleToggleAccessibilityScriptInjectionPreference(preference);
+            return true;
         }
-
         return super.onPreferenceTreeClick(preferenceScreen, preference);
     }
 
-    /**
-     * Handles the change of the accessibility enabled setting state.
-     *
-     * @param preference The preference for enabling/disabling accessibility.
-     */
-    private void handleEnableAccessibilityStateChange(CheckBoxPreference preference) {
-        if (preference.isChecked()) {
-            Settings.Secure.putInt(getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_ENABLED, 1);
-            setAccessibilityServicePreferencesState(true);
-        } else {
-            // set right enabled state since the user may press back
-            preference.setChecked(true);
-            showDialog(DIALOG_ID_DISABLE_ACCESSIBILITY);
+    private void handleTogglePowerButtonEndsCallPreference(CheckBoxPreference preference) {
+        Settings.Secure.putInt(getContentResolver(),
+                Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
+                (preference.isChecked() ? Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP
+                        : Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF));
+    }
+
+    private void handleToggleLargeTextPreference(CheckBoxPreference preference) {
+        try {
+            mCurConfig.fontScale = preference.isChecked() ? LARGE_FONT_SCALE : 1;
+            ActivityManagerNative.getDefault().updatePersistentConfiguration(mCurConfig);
+        } catch (RemoteException e) {
+            /* ignore */
         }
     }
 
-    /**
-     * Handles the change of the accessibility script injection setting state.
-     *
-     * @param preference The preference for enabling/disabling accessibility script injection.
-     */
-    private void handleToggleAccessibilityScriptInjection(CheckBoxPreference preference) {
-        if (preference.isChecked()) {
-            // set right enabled state since the user may press back
-            preference.setChecked(false);
+    private void handleToggleAccessibilityScriptInjectionPreference(Preference preference) {
+        String allowed = getString(R.string.accessibility_script_injection_disallowed);
+        if (preference.getSummary().equals(allowed)) {
+            // set right enabled state since the user may press back.
             showDialog(DIALOG_ID_ENABLE_SCRIPT_INJECTION);
         } else {
             Settings.Secure.putInt(getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0);
+                    Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0);
+            mToggleScriptInjectionPreference.setSummary(
+                    getString(R.string.accessibility_script_injection_disallowed));
         }
     }
 
-    /**
-     * Handles the change of the preference for enabling/disabling an AccessibilityService.
-     *
-     * @param preference The preference.
-     */
-    private void handleEnableAccessibilityServiceStateChange(
-            SettingsCheckBoxPreference preference) {
-        if (preference.isChecked()) {
-            mToggleAccessibilityServiceCheckBox = preference;
-            // set right enabled state since the user may press back
-            preference.setChecked(false);
-            showDialog(DIALOG_ID_ENABLE_ACCESSIBILITY_SERVICE);
-        } else {
-            persistEnabledAccessibilityServices();
-        }
-    }
-
-    /**
-     * Persists the Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES setting.
-     * The AccessibilityManagerService watches this property and manages the
-     * AccessibilityServices.
-     */
-    private void persistEnabledAccessibilityServices() {
-        StringBuilder builder = new StringBuilder(256);
-
-        for (String key : mAccessibilityServices.keySet()) {
-            CheckBoxPreference preference = (CheckBoxPreference) findPreference(key);
-            if (preference.isChecked()) {
-                 builder.append(key);
-                 builder.append(':');
+    private void installToggleAccessibilitySwitch() {
+        mToggleAccessibilitySwitch = createActionBarToggleSwitch(getActivity());
+        final boolean checked = (Settings.Secure.getInt(getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1);
+        mToggleAccessibilitySwitch.setChecked(checked);
+        mToggleAccessibilitySwitch.setOnBeforeCheckedChangeListener(
+                new OnBeforeCheckedChangeListener() {
+            @Override
+            public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
+                if (!checked) {
+                    toggleSwitch.setCheckedNoBeforeCheckedChangeListener(true);
+                    showDialog(DIALOG_ID_DISABLE_ACCESSIBILITY);
+                    return true;
+                }
+                Settings.Secure.putInt(getContentResolver(),
+                        Settings.Secure.ACCESSIBILITY_ENABLED, 1);
+                updatePreferencesForAccessibilityState();
+                return false;
             }
-        }
-
-        Settings.Secure.putString(getContentResolver(),
-            Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, builder.toString());
+        });
     }
 
-    /**
-     * Adds {@link CheckBoxPreference} for enabling or disabling an accessibility services.
-     */
-    private void addAccessibilityServicePreferences() {
-        AccessibilityManager accessibilityManager =
-            (AccessibilityManager) getSystemService(Service.ACCESSIBILITY_SERVICE);
+    private void findPreferences() {
+        mServicesCategory = (PreferenceCategory) findPreference(SERVICES_CATEGORY);
+
+        mToggleLargeTextPreference = (CheckBoxPreference) findPreference(
+                TOGGLE_LARGE_TEXT_PREFERENCE);
+        mTogglePowerButtonEndsCallPreference = (CheckBoxPreference) findPreference(
+                TOGGLE_POWER_BUTTON_ENDS_CALL_PREFERENCE);
+        mTouchExplorationEnabledPreference = findPreference(TOGGLE_TOUCH_EXPLORATION_PREFERENCE);
+        mSelectLongPressTimeoutPreference = (ListPreference) findPreference(
+                SELECT_LONG_PRESS_TIMEOUT_PREFERENCE);
+        mSelectLongPressTimeoutPreference.setOnPreferenceChangeListener(this);
+        mToggleScriptInjectionPreference = findPreference(TOGGLE_SCRIPT_INJECTION_PREFERENCE);
+        mToggleScriptInjectionPreference.setOnPreferenceChangeListener(this);
+    }
+
+    private void updateServicesPreferences() {
+        mServicesCategory.removeAll();
+
+        AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(getActivity());
 
         List<AccessibilityServiceInfo> installedServices =
             accessibilityManager.getInstalledAccessibilityServiceList();
 
-        for (int i = 0; i < mAccessibilityServicesCategory.getPreferenceCount(); i++) {
-            Preference pref = mAccessibilityServicesCategory.getPreference(i);
-            if (pref != mToggleAccessibilityCheckBox
-                    && pref != mToggleScriptInjectionCheckBox) {
-                mAccessibilityServicesCategory.removePreference(pref);
-                i--;
+        if (installedServices.isEmpty() && accessibilityManager.isEnabled()) {
+            // no service and accessibility is enabled => disable
+            Settings.Secure.putInt(getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED, 0);
+            mToggleAccessibilitySwitch.setChecked(false);
+            mToggleAccessibilitySwitch.setEnabled(false);
+            // Notify user that they do not have any accessibility
+            // services installed and direct them to Market to get TalkBack.
+            showDialog(DIALOG_ID_NO_ACCESSIBILITY_SERVICES);
+            return;
+        }
+
+        Set<ComponentName> enabledComponentNames = new HashSet<ComponentName>();
+        String settingValue = Settings.Secure.getString(getContentResolver(),
+                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+        if (settingValue != null) {
+            SimpleStringSplitter splitter = mStringColonSplitter;
+            splitter.setString(settingValue);
+            while (splitter.hasNext()) {
+                enabledComponentNames.add(ComponentName.unflattenFromString(splitter.next()));
             }
         }
 
         for (int i = 0, count = installedServices.size(); i < count; ++i) {
-            AccessibilityServiceInfo accessibilityServiceInfo = installedServices.get(i);
-            String key = accessibilityServiceInfo.getId();
+            AccessibilityServiceInfo info = installedServices.get(i);
+            String key = info.getId();
 
-            if (mAccessibilityServices.put(key, accessibilityServiceInfo) == null) {
-                SettingsCheckBoxPreference preference = null;
-                Intent settingsIntent = null;
-                String settingsActivityName = accessibilityServiceInfo.getSettingsActivityName();
+            PreferenceScreen preference = getPreferenceManager().createPreferenceScreen(
+                    getActivity());
+            String title = info.getResolveInfo().loadLabel(getPackageManager()).toString();
 
-                if (!TextUtils.isEmpty(settingsActivityName)) {
-                    settingsIntent = new Intent(Intent.ACTION_MAIN);
-                    settingsIntent.setClassName(
-                            accessibilityServiceInfo.getResolveInfo().serviceInfo.packageName,
-                            settingsActivityName);
-                }
+            ServiceInfo serviceInfo = info.getResolveInfo().serviceInfo;
+            ComponentName componentName = new ComponentName(serviceInfo.packageName,
+                    serviceInfo.name);
 
-                preference = new SettingsCheckBoxPreference(getActivity(), settingsIntent);
-                preference.setKey(key);
-                preference.setOrder(i);
-                ServiceInfo serviceInfo = accessibilityServiceInfo.getResolveInfo().serviceInfo;
-                preference.setTitle(serviceInfo.loadLabel(getActivity().getPackageManager()));
-                mAccessibilityServicesCategory.addPreference(preference);
+            preference.setKey(componentName.flattenToString());
+
+            preference.setTitle(title);
+            final boolean enabled = enabledComponentNames.contains(componentName);
+            if (enabled) {
+                preference.setSummary(getString(R.string.accessibility_service_state_on));
+            } else {
+                preference.setSummary(getString(R.string.accessibility_service_state_off));
             }
+
+            preference.setOrder(i);
+            preference.setFragment(ToggleAccessibilityServiceFragment.class.getName());
+
+            Bundle extras = preference.getExtras();
+            extras.putString(EXTRA_PREFERENCE_KEY, preference.getKey());
+            extras.putBoolean(EXTRA_CHECKED, enabled);
+            extras.putString(EXTRA_TITLE, title);
+            extras.putString(EXTRA_SUMMARY, info.getDescription());
+            extras.putString(EXTRA_WARNING_MESSAGE, getString(
+                    R.string.accessibility_service_security_warning,
+                    info.getResolveInfo().loadLabel(getPackageManager())));
+
+            String settingsClassName = info.getSettingsActivityName();
+            if (!TextUtils.isEmpty(settingsClassName)) {
+                extras.putString(EXTRA_SETTINGS_TITLE,
+                        getString(R.string.accessibility_menu_item_settings));
+                extras.putString(EXTRA_SETTINGS_COMPONENT_NAME,
+                        new ComponentName(info.getResolveInfo().serviceInfo.packageName,
+                                settingsClassName).flattenToString());
+            }
+
+            mServicesCategory.addPreference(preference);
         }
     }
 
-    public void readFontSizePreference() {
+    public void updateSystemPreferences() {
+        // Large text.
         try {
-            mCurConfig.updateFrom(
-                ActivityManagerNative.getDefault().getConfiguration());
-        } catch (RemoteException e) {
+            mCurConfig.updateFrom(ActivityManagerNative.getDefault().getConfiguration());
+        } catch (RemoteException re) {
+            /* ignore */
         }
-        mToggleLargeTextCheckBox.setChecked(Float.compare(mCurConfig.fontScale,
+        mToggleLargeTextPreference.setChecked(Float.compare(mCurConfig.fontScale,
                 LARGE_FONT_SCALE) == 0);
+
+        // Power button ends call.
+        if (KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_POWER)
+                && Utils.isVoiceCapable(getActivity())) {
+              final int incallPowerBehavior = Settings.Secure.getInt(getContentResolver(),
+                      Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
+                      Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT);
+              final boolean powerButtonEndsCall =
+                  (incallPowerBehavior == Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP);
+              mTogglePowerButtonEndsCallPreference.setChecked(powerButtonEndsCall);
+        } else {
+              getPreferenceScreen().removePreference(mTogglePowerButtonEndsCallPreference);
+        }
+
+        // Touch exploration enabled.
+        final boolean touchExplorationEnabled = (Settings.Secure.getInt(getContentResolver(),
+                Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1);
+        if (touchExplorationEnabled) {
+            mTouchExplorationEnabledPreference.setSummary(
+                    getString(R.string.accessibility_service_state_on));
+            mTouchExplorationEnabledPreference.getExtras().putBoolean(EXTRA_CHECKED, true);
+        } else {
+            mTouchExplorationEnabledPreference.setSummary(
+                    getString(R.string.accessibility_service_state_off));
+            mTouchExplorationEnabledPreference.getExtras().putBoolean(EXTRA_CHECKED, false);
+        }
+
+        // Long press timeout.
+        if (mLongPressTimeoutValuetoTitleMap.isEmpty()) {
+            String[] timeoutValues = getResources().getStringArray(
+                    R.array.long_press_timeout_selector_values);
+            String[] timeoutTitles = getResources().getStringArray(
+                    R.array.long_press_timeout_selector_titles);
+            final int timeoutValueCount = timeoutValues.length;
+            for (int i = 0;i < timeoutValueCount; i++) {
+                mLongPressTimeoutValuetoTitleMap.put(timeoutValues[i], timeoutTitles[i]);
+            }
+        }
+        String longPressTimeout = String.valueOf(Settings.Secure.getInt(getContentResolver(),
+                Settings.Secure.LONG_PRESS_TIMEOUT, 0));
+        mSelectLongPressTimeoutPreference.setSummary(
+                mLongPressTimeoutValuetoTitleMap.get(longPressTimeout));
+
+        // Script injection.
+        final boolean scriptInjectionAllowed = (Settings.Secure.getInt(getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0) == 1);
+        if (scriptInjectionAllowed) {
+            mToggleScriptInjectionPreference.setSummary(
+                    getString(R.string.accessibility_script_injection_allowed));
+        } else {
+            mToggleScriptInjectionPreference.setSummary(
+                    getString(R.string.accessibility_script_injection_disallowed));
+        }
     }
 
     @Override
@@ -460,11 +419,18 @@
                             public void onClick(DialogInterface dialog, int which) {
                                 Settings.Secure.putInt(getContentResolver(),
                                     Settings.Secure.ACCESSIBILITY_ENABLED, 0);
-                                mToggleAccessibilityCheckBox.setChecked(false);
-                                setAccessibilityServicePreferencesState(false);
+                                mToggleAccessibilitySwitch.setCheckedNoBeforeCheckedChangeListener(
+                                        false);
+                                updatePreferencesForAccessibilityState();
                             }
                     })
-                    .setNegativeButton(android.R.string.cancel, null)
+                    .setNegativeButton(android.R.string.cancel,
+                        new DialogInterface.OnClickListener() {
+                            public void onClick(DialogInterface dialog, int which) {
+                                mToggleAccessibilitySwitch.setCheckedNoBeforeCheckedChangeListener(
+                                        true);
+                            }
+                        })
                     .create();
             case DIALOG_ID_ENABLE_SCRIPT_INJECTION:
                 return new AlertDialog.Builder(getActivity())
@@ -473,35 +439,18 @@
                 .setMessage(getActivity().getString(
                         R.string.accessibility_script_injection_security_warning))
                 .setCancelable(true)
-                .setPositiveButton(android.R.string.ok,
+                .setPositiveButton(R.string.accessibility_script_injection_button_allow,
                     new DialogInterface.OnClickListener() {
                         public void onClick(DialogInterface dialog, int which) {
                             Settings.Secure.putInt(getContentResolver(),
                             Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 1);
-                            mToggleScriptInjectionCheckBox.setChecked(true);
+                            mToggleScriptInjectionPreference.setSummary(
+                                    getString(R.string.accessibility_script_injection_allowed));
                         }
                 })
-                .setNegativeButton(android.R.string.cancel, null)
+
+                .setNegativeButton(R.string.accessibility_script_injection_button_disallow, null)
                 .create();
-            case DIALOG_ID_ENABLE_ACCESSIBILITY_SERVICE:
-                return new AlertDialog.Builder(getActivity())
-                    .setTitle(android.R.string.dialog_alert_title)
-                    .setIcon(android.R.drawable.ic_dialog_alert)
-                    .setMessage(getResources().getString(
-                            R.string.accessibility_service_security_warning,
-                            mAccessibilityServices.get(mToggleAccessibilityServiceCheckBox.getKey())
-                            .getResolveInfo().serviceInfo.applicationInfo.loadLabel(
-                                    getActivity().getPackageManager())))
-                    .setCancelable(true)
-                    .setPositiveButton(android.R.string.ok,
-                            new DialogInterface.OnClickListener() {
-                                public void onClick(DialogInterface dialog, int which) {
-                                    mToggleAccessibilityServiceCheckBox.setChecked(true);
-                                    persistEnabledAccessibilityServices();
-                                }
-                    })
-                    .setNegativeButton(android.R.string.cancel, null)
-                    .create();
             case DIALOG_ID_NO_ACCESSIBILITY_SERVICES:
                 return new AlertDialog.Builder(getActivity())
                     .setTitle(R.string.accessibility_service_no_apps_title)
@@ -526,4 +475,264 @@
                 return null;
         }
     }
+
+    private class SettingsPackageMonitor extends PackageMonitor {
+
+        @Override
+        public void onPackageAdded(String packageName, int uid) {
+            Message message = mHandler.obtainMessage();
+            mHandler.sendMessageDelayed(message, DELAY_UPDATE_SERVICES_PREFERENCES_MILLIS);
+        }
+
+        @Override
+        public void onPackageAppeared(String packageName, int reason) {
+            Message message = mHandler.obtainMessage();
+            mHandler.sendMessageDelayed(message, DELAY_UPDATE_SERVICES_PREFERENCES_MILLIS);
+        }
+
+        @Override
+        public void onPackageDisappeared(String packageName, int reason) {
+            Message message = mHandler.obtainMessage();
+            mHandler.sendMessageDelayed(message, DELAY_UPDATE_SERVICES_PREFERENCES_MILLIS);
+        }
+
+        @Override
+        public void onPackageRemoved(String packageName, int uid) {
+            Message message = mHandler.obtainMessage();
+            mHandler.sendMessageDelayed(message, DELAY_UPDATE_SERVICES_PREFERENCES_MILLIS);
+        }
+    }
+
+    private static ToggleSwitch createActionBarToggleSwitch(Activity activity) {
+        ToggleSwitch toggleSwitch = new ToggleSwitch(activity);
+        final int padding = activity.getResources().getDimensionPixelSize(
+                R.dimen.action_bar_switch_padding);
+        toggleSwitch.setPadding(0, 0, padding, 0);
+        activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
+                ActionBar.DISPLAY_SHOW_CUSTOM);
+        activity.getActionBar().setCustomView(toggleSwitch,
+                new ActionBar.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT,
+                        ActionBar.LayoutParams.WRAP_CONTENT,
+                        Gravity.CENTER_VERTICAL | Gravity.RIGHT));
+        return toggleSwitch;
+    }
+
+    public static class ToggleSwitch extends Switch {
+
+        private OnBeforeCheckedChangeListener mOnBeforeListener;
+
+        public static interface OnBeforeCheckedChangeListener {
+            public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked);
+        }
+
+        public ToggleSwitch(Context context) {
+            super(context);
+        }
+
+        public void setOnBeforeCheckedChangeListener(OnBeforeCheckedChangeListener listener) {
+            mOnBeforeListener = listener;
+        }
+
+        @Override
+        public void setChecked(boolean checked) {
+            if (mOnBeforeListener != null
+                    && mOnBeforeListener.onBeforeCheckedChanged(this, checked)) {
+                return;
+            }
+            super.setChecked(checked);
+        }
+
+        public void setCheckedNoBeforeCheckedChangeListener(boolean checked) {
+            super.setChecked(checked);
+        }
+    }
+
+    public static class ToggleAccessibilityServiceFragment extends TogglePreferenceFragment {
+        @Override
+        public void onPreferenceToggled(String preferenceKey, boolean enabled) {
+            String enabledServices = Settings.Secure.getString(getContentResolver(),
+                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+            if (enabledServices == null) {
+                enabledServices = "";
+            }
+            final int length = enabledServices.length();
+            if (enabled) {
+                if (enabledServices.contains(preferenceKey)) {
+                    return;
+                }
+                if (length == 0) {
+                    enabledServices += preferenceKey;
+                    Settings.Secure.putString(getContentResolver(),
+                            Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, enabledServices);
+                } else if (length > 0) {
+                    enabledServices += ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR + preferenceKey;
+                    Settings.Secure.putString(getContentResolver(),
+                            Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, enabledServices);
+                }
+            } else {
+                final int index = enabledServices.indexOf(preferenceKey);
+                if (index == 0) {
+                    enabledServices = enabledServices.replace(preferenceKey, "");
+                    Settings.Secure.putString(getContentResolver(),
+                            Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, enabledServices);
+                } else if (index > 0) {
+                    enabledServices = enabledServices.replace(
+                            ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR + preferenceKey, "");
+                    Settings.Secure.putString(getContentResolver(),
+                            Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, enabledServices);
+                }
+            }
+        }
+    }
+
+    public static class ToggleTouchExplorationFragment extends TogglePreferenceFragment {
+        @Override
+        public void onPreferenceToggled(String preferenceKey, boolean enabled) {
+            Settings.Secure.putInt(getContentResolver(),
+                    Settings.Secure.TOUCH_EXPLORATION_ENABLED, enabled ? 1 : 0);
+        }
+    }
+
+    private abstract static class TogglePreferenceFragment extends SettingsPreferenceFragment
+            implements DialogInterface.OnClickListener {
+
+        private static final int DIALOG_ID_WARNING = 1;
+
+        private String mPreferenceKey;
+
+        private ToggleSwitch mToggleSwitch;
+
+        private CharSequence mWarningMessage;
+        private Preference mSummaryPreference;
+
+        private CharSequence mSettingsTitle;
+        private Intent mSettingsIntent;
+
+        @Override
+        public void onActivityCreated(Bundle savedInstanceState) {
+            installActionBarToggleSwitch();
+            processArguments();
+            getListView().setDivider(null);
+            getListView().setEnabled(false);
+            super.onActivityCreated(savedInstanceState);
+        }
+
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            PreferenceScreen preferenceScreen = getPreferenceManager().createPreferenceScreen(
+                    getActivity());
+            setPreferenceScreen(preferenceScreen);
+            mSummaryPreference = new Preference(getActivity()) {
+                @Override
+                protected void onBindView(View view) {
+                    super.onBindView(view);
+                    TextView summaryView = (TextView) view.findViewById(R.id.summary);
+                    summaryView.setText(getSummary());
+                }
+            };
+            mSummaryPreference.setPersistent(false);
+            mSummaryPreference.setLayoutResource(R.layout.text_description_preference);
+            preferenceScreen.addPreference(mSummaryPreference);
+        }
+
+        public abstract void onPreferenceToggled(String preferenceKey, boolean value);
+
+        @Override
+        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+            super.onCreateOptionsMenu(menu, inflater);
+            MenuItem menuItem = menu.add(mSettingsTitle);
+            menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+            menuItem.setIntent(mSettingsIntent);
+        }
+
+        @Override
+        public Dialog onCreateDialog(int dialogId) {
+            switch (dialogId) {
+                case DIALOG_ID_WARNING:
+                    return new AlertDialog.Builder(getActivity())
+                        .setTitle(android.R.string.dialog_alert_title)
+                        .setIcon(android.R.drawable.ic_dialog_alert)
+                        .setMessage(mWarningMessage)
+                        .setCancelable(true)
+                        .setPositiveButton(android.R.string.ok, this)
+                        .setNegativeButton(android.R.string.cancel, this)
+                        .create();
+                default:
+                    throw new IllegalArgumentException();
+            }
+        }
+
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+            switch (which) {
+                case DialogInterface.BUTTON_POSITIVE:
+                    // OK, we got the user consent so set checked.
+                    mToggleSwitch.setCheckedNoBeforeCheckedChangeListener(true);
+                    onPreferenceToggled(mPreferenceKey, true);
+                    break;
+                case DialogInterface.BUTTON_NEGATIVE:
+                    onPreferenceToggled(mPreferenceKey, false);
+                    break;
+                default:
+                    throw new IllegalArgumentException();
+            }
+        }
+
+        private void installActionBarToggleSwitch() {
+            mToggleSwitch = createActionBarToggleSwitch(getActivity());
+            mToggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
+                @Override
+                public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
+                    if (checked) {
+                        if (!TextUtils.isEmpty(mWarningMessage)) {
+                            toggleSwitch.setCheckedNoBeforeCheckedChangeListener(false);
+                            showDialog(DIALOG_ID_WARNING);
+                            return true;
+                        }
+                        onPreferenceToggled(mPreferenceKey, true);
+                    } else {
+                        onPreferenceToggled(mPreferenceKey, false);
+                    }
+                    return false;
+                }
+            });
+        }
+
+        private void processArguments() {
+            Bundle arguments = getArguments();
+
+            // Key.
+            mPreferenceKey = arguments.getString(EXTRA_PREFERENCE_KEY);
+
+            // Enabled.
+            final boolean enabled = arguments.getBoolean(EXTRA_CHECKED);
+            mToggleSwitch.setCheckedNoBeforeCheckedChangeListener(enabled);
+
+            // Title.
+            String title = arguments.getString(EXTRA_TITLE);
+            getActivity().getActionBar().setTitle(arguments.getCharSequence(EXTRA_TITLE));
+
+            // Summary.
+            String summary = arguments.getString(EXTRA_SUMMARY);
+            mSummaryPreference.setSummary(summary);
+
+            // Settings title and intent.
+            String settingsTitle = arguments.getString(EXTRA_SETTINGS_TITLE);
+            String settingsComponentName = arguments.getString(EXTRA_SETTINGS_COMPONENT_NAME);
+            if (!TextUtils.isEmpty(settingsTitle) && !TextUtils.isEmpty(settingsComponentName)) {
+                Intent settingsIntent = new Intent(Intent.ACTION_MAIN).setComponent(
+                        ComponentName.unflattenFromString(settingsComponentName.toString()));
+                if (!getPackageManager().queryIntentActivities(settingsIntent, 0).isEmpty()) {
+                    mSettingsTitle = settingsTitle;
+                    mSettingsIntent = settingsIntent;
+                    setHasOptionsMenu(true);
+                }
+            }
+
+            // Waring message.
+            mWarningMessage = arguments.getCharSequence(
+                    AccessibilitySettings.EXTRA_WARNING_MESSAGE);
+        }
+    }
 }
diff --git a/src/com/android/settings/SettingsCheckBoxPreference.java b/src/com/android/settings/SettingsCheckBoxPreference.java
deleted file mode 100644
index 70b5ac1..0000000
--- a/src/com/android/settings/SettingsCheckBoxPreference.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings;
-
-import android.content.Context;
-import android.content.Intent;
-import android.preference.CheckBoxPreference;
-import android.util.TypedValue;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.CheckBox;
-import android.widget.ImageView;
-
-/**
- * CheckBox preference that optionally shows an icon for launching a settings
- * {@link android.app.Activity}. The settings activity, if intent for launching
- * it was provided, can be stared only if the CheckBox in is checked.
- */
-public class SettingsCheckBoxPreference extends CheckBoxPreference {
-
-    // Integer.MIN_VALUE means not initalized
-    private static int sDimAlpha = Integer.MIN_VALUE;
-
-    private final Intent mSettingsIntent;
-
-    /**
-     * Creates a new instance. The constructor is checking whether the
-     * settings intent is resolved to an activity and acts accordingly.
-     *
-     * @param context Context for accessing resources.
-     * @param intent Intent to use as settings for the item represented by
-     *        this preference. Pass <code>null</code> if there is no associated 
-     *        settings activity.
-     */
-    public SettingsCheckBoxPreference(Context context, Intent intent) {
-        super(context);
-
-        if (sDimAlpha == Integer.MIN_VALUE) {
-            TypedValue outValue = new TypedValue();
-            context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true);
-            sDimAlpha = (int) (outValue.getFloat() * 255);
-        }
-
-        if (intent != null
-                && !context.getPackageManager().queryIntentActivities(intent, 0).isEmpty()) {
-            mSettingsIntent = intent;
-        } else {
-            mSettingsIntent = null;
-        }
-
-        setWidgetLayoutResource(R.layout.preference_settings_checkbox_widget);
-    }
-
-    @Override
-    protected void onBindView(View view) {
-        super.onBindView(view);
-        ImageView settingsButton = (ImageView) view.findViewById(R.id.settings_button);
-        if (mSettingsIntent != null) {
-            CheckBox checkbox = (CheckBox) view.findViewById(com.android.internal.R.id.checkbox);
-            if (checkbox.isChecked()) {
-                settingsButton.setOnClickListener(new OnClickListener() {
-                    public void onClick(View view) {
-                        getContext().startActivity(mSettingsIntent);
-                    }
-                });
-            }
-            settingsButton.setVisibility(View.VISIBLE);
-            if (checkbox.isChecked() && isEnabled()) {
-                settingsButton.setAlpha(255);
-            } else {
-                settingsButton.setAlpha(sDimAlpha);
-            }
-        } else {
-            settingsButton.setVisibility(View.GONE);
-            view.findViewById(R.id.divider).setVisibility(View.GONE);
-        }
-    }
-}