Merge "Minor changes on bug report settings on 'Developer options'."
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index e5f1988..b3e2655 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -150,69 +150,6 @@
         <item>1.30</item>
     </string-array>
 
-    <!-- TTS settings -->
-
-    <!-- Default speech rate choices -->
-    <string-array name="tts_rate_entries">
-        <item>Very slow</item>
-        <item>Slow</item>
-        <item>Normal</item>
-        <item>Fast</item>
-        <item>Faster</item>
-        <item>Very fast</item>
-        <item>Rapid</item>
-        <item>Very rapid</item>
-        <item>Fastest</item>
-    </string-array>
-    <!-- Do not translate. -->
-    <string-array name="tts_rate_values">
-        <item>60</item>
-        <item>80</item>
-        <item>100</item>
-        <item>150</item>
-        <item>200</item>
-        <item>250</item>
-        <item>300</item>
-        <item>350</item>
-        <item>400</item>
-    </string-array>
-
-    <!-- Default pitch choices -->
-    <string-array name="tts_pitch_entries">
-        <item>Very low</item>
-        <item>Low</item>
-        <item>Normal</item>
-        <item>High</item>
-        <item>Very high</item>
-    </string-array>
-    <!-- Do not translate. -->
-    <string-array name="tts_pitch_values">
-        <item>50</item>
-        <item>80</item>
-        <item>100</item>
-        <item>120</item>
-        <item>150</item>
-    </string-array>
-
-    <!-- Do not translate. -->
-    <string-array name="tts_demo_strings" translatable="false">
-        <item>This is an example of speech synthesis in English.</item>
-        <item>Voici un échantillon de synthèse vocale en français.</item>
-        <item>Dies ist ein Beispiel für Sprachsynthese in Deutsch.</item>
-        <item>Questo è un esempio di sintesi vocale in italiano.</item>
-        <item>Este es un ejemplo de síntesis de voz en español.</item>
-        <item>이것은 한국어 음성 합성의 예입니다.</item>
-    </string-array>
-    <string-array name="tts_demo_string_langs" translatable="false">
-        <item>eng</item>
-        <item>fra</item>
-        <item>deu</item>
-        <item>ita</item>
-        <item>spa</item>
-        <item>kor</item>
-    </string-array>
-
-
     <!-- Wi-Fi settings -->
 
     <!-- Match this with the order of NetworkInfo.DetailedState. --> <skip />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9c314c3..aef3f78 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4459,124 +4459,6 @@
         behalf.  It comes from the <xliff:g id="voice_input_service_app_name">%s</xliff:g>
         application.  Enable the use of this service?</string>
 
-    <!-- Text-To-Speech (TTS) settings --><skip />
-    <!-- Name of the TTS package as listed by the package manager. -->
-    <string name="tts_settings">Text-to-speech settings</string>
-    <!-- TTS option item name in the main settings screen -->
-    <string name="tts_settings_title">Text-to-speech output</string>
-    <!-- On main TTS Settings screen, title for toggle used to force use of default TTS settings -->
-    <string name="use_default_tts_settings_title">Always use my settings</string>
-    <!-- On main TTS Settings screen, summary for toggle used to force use of default TTS settings -->
-    <string name="use_default_tts_settings_summary">Default settings below override app settings</string>
-    <!-- On main TTS Settings screen, section header for default TTS settings -->
-    <string name="tts_default_settings_section">Default settings</string>
-    <!-- On main TTS Settings screen, in default settings section, setting default synthesis engine for synthesized voice -->
-    <string name="tts_default_synth_title">Default engine</string>
-    <!-- On main TTS Settings screen, summary for default synthesis engine for synthesized voice -->
-    <string name="tts_default_synth_summary">Set the speech synthesis engine to be used for spoken text</string>
-    <!-- On main TTS Settings screen, in default settings section, setting default speech rate for synthesized voice -->
-    <string name="tts_default_rate_title">Speech rate</string>
-    <!-- On main TTS Settings screen, summary for default speech rate for synthesized voice -->
-    <string name="tts_default_rate_summary">Speed at which the text is spoken</string>
-    <!-- On main TTS Settings screen, in default settings section, setting default pitch for synthesized voice -->
-    <string name="tts_default_pitch_title">Pitch</string>
-    <!-- On main TTS Settings screen, summary for default pitch for synthesized voice -->
-    <string name="tts_default_pitch_summary">Affects the tone of the spoken text</string>
-
-    <!-- On main TTS Settings screen, in default settings section, setting default language for synthesized voice -->
-    <string name="tts_default_lang_title">Language</string>
-    <!-- Entry in the TTS engine language/locale picker, when selected will try to default to the system language [CHAR LIMIT=50] -->
-    <string name="tts_lang_use_system">Use system language</string>
-    <!-- On main TTS Settings screen, language summary if it can't default to system language [CHAR LIMIT=50] -->
-    <string name="tts_lang_not_selected">Language not selected</string>
-    <!-- On main TTS Settings screen, summary for default language for synthesized voice -->
-    <string name="tts_default_lang_summary">Sets the language-specific voice for the spoken text</string>
-    <!-- On main TTS Settings screen, triggers playback of an example of speech synthesis -->
-    <string name="tts_play_example_title">Listen to an example</string>
-    <!-- On main TTS Settings screen, summary for triggering playback of an example of speech synthesis -->
-    <string name="tts_play_example_summary">Play a short demonstration of speech synthesis</string>
-    <!-- On main TTS Settings screen, click to install required speech synthesis data -->
-    <string name="tts_install_data_title">Install voice data</string>
-    <!-- On main TTS Settings screen, summary for click to install required speech synthesis data -->
-    <string name="tts_install_data_summary">Install the voice data required for speech synthesis</string>
-    <!-- On main TTS Settings screen, summary for when required speech synthesis data alrady installed on SD card -->
-    <string name="tts_data_installed_summary">Voices required for speech synthesis already properly installed</string>
-    <!-- Text spoken by the TTS engine when TTS settings (other than language) have been changed -->
-    <string name="tts_settings_changed_demo">Your settings have changed. This is an example of how they sound.</string>
-    <!-- Error screen when a selected TTS engine can't run because it's missing components -->
-    <string name="tts_engine_error">The engine you chose can\u2019t run.</string>
-    <!-- Button text for error screen when a selected TTS engine can't run because it's missing components -->
-    <string name="tts_engine_error_config">Configure</string>
-    <!-- Button text for error screen when a selected TTS engine can't run because it's missing components -->
-    <string name="tts_engine_error_reselect">Choose another engine</string>
-    <!-- Warning message about security implications of enabling a TTS engine, displayed as a dialog
-         message when the user selects to enable an engine. -->
-    <string name="tts_engine_security_warning">This speech synthesis engine may be able to collect
-    all the text that will be spoken, including personal data like passwords and credit
-    card numbers. It comes from the <xliff:g id="tts_plugin_engine_name">%s</xliff:g> engine.
-    Enable the use of this speech synthesis engine?</string>
-    <!-- Warning message about required internet conectivity for TTS synthesis, displayed as a dialog
-         message when the user selects to play an example for network only locale and there's no internet connectivity. -->
-    <string name="tts_engine_network_required">This language requires a working network connection for text-to-speech output.</string>
-    <!-- Text spoken by the TTS engine as an example if the engine doesn't provide sample text [CHAR LIMIT=100] -->
-    <string name="tts_default_sample_string">This is an example of speech synthesis</string>
-    <!-- On main TTS Settings screen, title of a field explaining current TTS engine status for
-         current default language [CHAR LIMIT=50] -->
-    <string name="tts_status_title">Default language status</string>
-    <!-- On main TTS Settings screen, current TTS engine status for the current default language,
-         selected language is fully supported by the engine [CHAR LIMIT=150]-->
-    <string name="tts_status_ok"><xliff:g id="locale" example="English (United States)">%1$s</xliff:g> is fully supported</string>
-    <!-- On main TTS Settings screen, current TTS engine status for the current default language,
-         selected language is supported by the engine only if there's a working network connection [CHAR LIMIT=150] -->
-    <string name="tts_status_requires_network"><xliff:g id="locale" example="English (United States)">%1$s</xliff:g> requires network connection</string>
-    <!-- On main TTS Settings screen, current TTS engine status for the current default language,
-         selected language is not supported by the engine [CHAR LIMIT=150] -->
-    <string name="tts_status_not_supported"><xliff:g id="locale" example="English (United States)">%1$s</xliff:g> is not supported</string>
-    <!-- On main TTS Settings screen, current TTS engine status for the current default language,
-         tts engine is queried for status [CHAR LIMIT=150] -->
-    <string name="tts_status_checking">Checking...</string>
-    <!-- On main TTS Settings screen, text for divider under which all TTS engines are listed -->
-    <string name="tts_engines_section">Engines</string>
-    <!-- On main TTS Settings screen, text preceded by the TTS engine name, clicking this button will launch the engine settings -->
-    <string name="tts_engine_name_settings"><xliff:g id="tts_plugin_engine_name">%s</xliff:g> settings</string>
-    <!-- On main TTS Settings screen, text preceded by the TTS engine name to indicate the engine can be used by the user -->
-    <string name="tts_engine_name_is_enabled_summary"><xliff:g id="tts_plugin_engine_name">%s</xliff:g> is enabled</string>
-    <!-- On main TTS Settings screen, text preceded by the TTS engine name to indicate the engine cannot be used by the user -->
-    <string name="tts_engine_name_is_disabled_summary"><xliff:g id="tts_plugin_engine_name">%s</xliff:g> is disabled</string>
-    <!-- On the main TTS settings screen, text for a divider under which
-         the engine specific settings and the "engine install data" option
-         are listed [CHAR LIMIT=30]-->
-    <string name="tts_engine_settings_section">Engine settings</string>
-    <!-- Title for a preference in the main TTS settings screen, which
-         launches the settings screen for a given TTS engine when clicked
-         [CHAR LIMIT=30]-->
-    <string name="tts_engine_settings_title">Settings for <xliff:g id="tts_engine_name">%s</xliff:g></string>
-    <!-- On Pico TTS Settings screen, text to mark the section for the various languages and voices that are available -->
-    <string name="pico_languages_and_voices">Languages and voices</string>
-    <!-- On Pico TTS Settings screen, text to mark a voice as installed -->
-    <string name="pico_installed">Installed</string>
-    <!-- On Pico TTS Settings screen, text to mark a voice as not installed -->
-    <string name="pico_not_installed">Not installed</string>
-    <!-- On Pico TTS Settings screen, summary text to indicate that a voice is female -->
-    <string name="pico_voice_summary_female">Female</string>
-    <!-- On Pico TTS Settings screen, summary text to indicate that a voice is male -->
-    <string name="pico_voice_summary_male">Male</string>
-    <!-- [CHAR LIMIT=33] Notification title that appears when the installation of a new TTS engine completed -->
-    <string name="tts_notif_engine_install_title">Speech synthesis engine installed</string>
-    <!-- [CHAR LIMIT=30] Notification message that appears after the user has installed a new TTS engine,
-         to warn the user that this engine cannot be used before the checkbox for that engine
-         in TTS settings is checked. -->
-    <string name="tts_notif_engine_install_message">Enable new engine before use.</string>
-    <!-- [CHAR LIMIT=150] Text for screen readers / accessibility programs for
-         the image that launches the TTS engine settings when clicked. -->
-    <string name="tts_engine_settings_button">Launch engine settings</string>
-    <!-- [CHAR LIMIT=50] The text for the settings section that users to set a
-         preferred text to speech engine -->
-    <string name="tts_engine_preference_section_title">Preferred engine</string>
-    <!-- [CHAR LIMIT=50] Title of the settings section that displays general preferences
-         that are applicable to all engines, such as the speech rate -->
-    <string name="tts_general_section_title">General</string>
-
     <!-- Power Control Widget -->
     <string name="gadget_title">Power control</string>
     <string name="gadget_toggle_wifi">Updating Wi\u2011Fi setting</string>
@@ -7096,4 +6978,22 @@
 
     <!-- Description of feature to change color setting for the display [CHAR LIMIT=NONE] -->
     <string name="picture_color_mode_desc">Use sRGB</string>
+
+    <!-- Title of setting that controls display scale (e.g. density). [CHAR LIMIT=40] -->
+    <string name="force_density_preference_title">Display scale</string>
+    <!-- Keywords for setting that controls display scale (e.g. density). [CHAR LIMIT=NONE] -->
+    <string name="force_density_keywords">display density zoom scale scaling</string>
+    <!-- Description for the display scale that makes interface elements small. [CHAR LIMIT=24] -->
+    <string name="force_density_summary_small">Small</string>
+    <!-- Description for the device's default display scale. [CHAR LIMIT=24] -->
+    <string name="force_density_summary_normal">Normal</string>
+    <!-- Description for the display scale that makes interface elements large. [CHAR LIMIT=24] -->
+    <string name="force_density_summary_large">Large</string>
+    <!-- Description for the display scale that makes interface elements larger. [CHAR LIMIT=24] -->
+    <string name="force_density_summary_very_large">Larger</string>
+    <!-- Description for the display scale that makes interface elements largest. [CHAR LIMIT=24] -->
+    <string name="force_density_summary_extremely_large">Largest</string>
+    <!-- Description for a custom display scale. This shows the requested display
+         density in raw pixels per inch rather than computing a scale amount. [CHAR LIMIT=24] -->
+    <string name="force_density_summary_custom">Custom (<xliff:g id="densityDpi" example="160">%d</xliff:g>)</string>
 </resources>
diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml
index ad23bc2..60730a9 100644
--- a/res/xml/display_settings.xml
+++ b/res/xml/display_settings.xml
@@ -99,6 +99,13 @@
                 android:entries="@array/entries_font_size"
                 android:entryValues="@array/entryvalues_font_size" />
 
+        <com.android.settings.DisplayDensityPreference
+                android:key="display_density"
+                android:title="@string/force_density_preference_title"
+                android:summary="%s"
+                settings:keywords="@string/force_density_keywords"
+                android:persistent="false" />
+
         <com.android.settings.DropDownPreference
                 android:key="auto_rotate"
                 android:title="@string/display_auto_rotate_title" />
diff --git a/src/com/android/settings/DisplayDensityPreference.java b/src/com/android/settings/DisplayDensityPreference.java
new file mode 100644
index 0000000..85f2fb2
--- /dev/null
+++ b/src/com/android/settings/DisplayDensityPreference.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2015 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.res.Resources;
+import android.os.AsyncTask;
+import android.os.RemoteException;
+import android.support.annotation.ArrayRes;
+import android.support.v7.preference.ListPreference;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.MathUtils;
+import android.view.Display;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
+
+import com.android.settings.R;
+
+import java.util.Arrays;
+
+/**
+ * Preference for changing the density of the display on which the preference
+ * is visible.
+ */
+public class DisplayDensityPreference extends ListPreference {
+    private static final String LOG_TAG = "DisplayDensityPreference";
+
+    /** Minimum increment between density scales. */
+    private static final float MIN_SCALE_INTERVAL = 0.09f;
+
+    /** Minimum density scale. This is available on all devices. */
+    private static final float MIN_SCALE = 0.85f;
+
+    /** Maximum density scale. The actual scale used depends on the device. */
+    private static final float MAX_SCALE = 1.50f;
+
+    /** Sentinel value for "normal" scaling (effectively disabled). */
+    private static final int DENSITY_VALUE_NORMAL = -1;
+
+    /** Summary used for "normal" scale. */
+    private static final int DENSITY_SUMMARY_NORMAL = R.string.force_density_summary_normal;
+
+    /**
+     * Summaries for scales smaller than "normal" in order of smallest to
+     * largest.
+     */
+    private static final int[] SMALLER_SUMMARIES = new int[] {
+            R.string.force_density_summary_small
+    };
+
+    /**
+     * Summaries for scales larger than "normal" in order of smallest to
+     * largest.
+     */
+    private static final int[] LARGER_SUMMARIES = new int[] {
+            R.string.force_density_summary_large,
+            R.string.force_density_summary_very_large,
+            R.string.force_density_summary_extremely_large,
+    };
+
+    /**
+     * Minimum allowed screen dimension, corresponds to resource qualifiers
+     * "small" or "sw320dp". This value must be at least the minimum screen
+     * size required by the CDD so that we meet developer expectations.
+     */
+    private static final int MIN_DIMENSION_DP = 320;
+
+    /** The ID of the display affected by this preference. */
+    private int mDisplayId = Display.DEFAULT_DISPLAY;
+
+    public DisplayDensityPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        if (!prepareList()) {
+            setEnabled(false);
+        }
+    }
+
+    private boolean prepareList() {
+        final int initialDensity = getInitialDisplayDensity(mDisplayId);
+        if (initialDensity <= 0) {
+            return false;
+        }
+
+        final Resources res = getContext().getResources();
+        final DisplayMetrics metrics = res.getDisplayMetrics();
+        final int currentDensity = metrics.densityDpi;
+        int currentDensityIndex = -1;
+
+        // Compute number of "larger" and "smaller" scales for this display.
+        final int minDimensionPx = Math.min(metrics.widthPixels, metrics.heightPixels);
+        final int maxDensity = DisplayMetrics.DENSITY_MEDIUM * minDimensionPx / MIN_DIMENSION_DP;
+        final float maxScale = Math.min(MAX_SCALE, maxDensity / (float) initialDensity);
+        final float minScale = MIN_SCALE;
+        final int numLarger = (int) MathUtils.constrain((maxScale - 1) / MIN_SCALE_INTERVAL,
+                0, LARGER_SUMMARIES.length);
+        final int numSmaller = (int) MathUtils.constrain((1 - minScale) / MIN_SCALE_INTERVAL,
+                0, SMALLER_SUMMARIES.length);
+
+        CharSequence[] values = new CharSequence[1 + numSmaller + numLarger];
+        CharSequence[] entries = new CharSequence[values.length];
+        int curIndex = 0;
+
+        if (numSmaller > 0) {
+            final float interval = (1 - minScale) / numSmaller;
+            for (int i = numSmaller - 1; i >= 0; i--) {
+                final int density = (int) (initialDensity * (1 - (i + 1) * interval));
+                if (currentDensity == density) {
+                    currentDensityIndex = curIndex;
+                }
+                values[curIndex] = Integer.toString(density);
+                entries[curIndex] = res.getText(SMALLER_SUMMARIES[i]);
+                curIndex++;
+            }
+        }
+
+        if (currentDensity == initialDensity) {
+            currentDensityIndex = curIndex;
+        }
+        values[curIndex] = Integer.toString(DENSITY_VALUE_NORMAL);
+        entries[curIndex] = res.getText(DENSITY_SUMMARY_NORMAL);
+        curIndex++;
+
+        if (numLarger > 0) {
+            final float interval = (maxScale - 1) / numLarger;
+            for (int i = 0; i < numLarger; i++) {
+                final int density = (int) (initialDensity * (1 + (i + 1) * interval));
+                if (currentDensity == density) {
+                    currentDensityIndex = curIndex;
+                }
+                values[curIndex] = Integer.toString(density);
+                entries[curIndex] = res.getText(LARGER_SUMMARIES[i]);
+                curIndex++;
+            }
+        }
+
+        final int displayIndex;
+        if (currentDensityIndex >= 0) {
+            displayIndex = currentDensityIndex;
+        } else {
+            // We don't understand the current density. Must have been set by
+            // someone else. Make room for another entry...
+            values = Arrays.copyOf(values, values.length + 1);
+            values[curIndex] = res.getString(R.string.force_density_summary_custom, currentDensity);
+
+            entries = Arrays.copyOf(entries, values.length + 1);
+            entries[curIndex] = Integer.toString(currentDensity);
+
+            displayIndex = curIndex;
+        }
+
+        super.setEntryValues(values);
+        super.setEntries(entries);
+
+        setValueIndex(displayIndex);
+
+        return true;
+    }
+
+    @Override
+    public boolean callChangeListener(Object newValue) {
+        final boolean allowed = super.callChangeListener(newValue);
+        if (allowed) {
+            final int density = Integer.parseInt((String) newValue);
+            setForcedDisplayDensity(mDisplayId, density);
+        }
+
+        return allowed;
+    }
+
+    @Override
+    public void setEntries(CharSequence[] entries) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setEntries(@ArrayRes int entriesResId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setEntryValues(CharSequence[] entryValues) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setEntryValues(@ArrayRes int entryValuesResId) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns the initial density for the specified display.
+     *
+     * @param displayId the identifier of the display
+     * @return the initial density of the specified display, or {@code -1} if
+     *         the display does not exist or the density could not be obtained
+     */
+    private static int getInitialDisplayDensity(int displayId) {
+        try {
+            IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+            return wm.getInitialDisplayDensity(displayId);
+        } catch (RemoteException exc) {
+            return -1;
+        }
+    }
+
+    /**
+     * Asynchronously applies display density changes to the specified display.
+     *
+     * @param displayId the identifier of the display to modify
+     * @param density the density to force for the specified display, or <= 0
+     *                to clear any previously forced density
+     */
+    private static void setForcedDisplayDensity(final int displayId, final int density) {
+        AsyncTask.execute(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+                    if (density <= 0) {
+                        wm.clearForcedDisplayDensity(displayId);
+                    } else {
+                        wm.setForcedDisplayDensity(displayId, density);
+                    }
+                } catch (RemoteException exc) {
+                    Log.w(LOG_TAG, "Unable to save forced display density setting");
+                }
+            }
+        });
+    }
+}
diff --git a/src/com/android/settings/DisplaySettings.java b/src/com/android/settings/DisplaySettings.java
index 8e32322..e26200a 100644
--- a/src/com/android/settings/DisplaySettings.java
+++ b/src/com/android/settings/DisplaySettings.java
@@ -76,6 +76,7 @@
     private static final String KEY_CAMERA_GESTURE = "camera_gesture";
     private static final String KEY_CAMERA_DOUBLE_TAP_POWER_GESTURE
             = "camera_double_tap_power_gesture";
+    private static final String KEY_DISPLAY_DENSITY = "display_density";
 
     private DropDownPreference mFontSizePref;
 
@@ -213,6 +214,9 @@
             mNightModePreference.setValue(String.valueOf(currentNightMode));
             mNightModePreference.setOnPreferenceChangeListener(this);
         }
+
+        final Preference displayDensity = findPreference(KEY_DISPLAY_DENSITY);
+        displayDensity.setOnPreferenceChangeListener(this);
     }
 
     private static boolean allowAllRotations(Context context) {
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index 52e1b8a..870cb20 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -127,7 +127,6 @@
     private final Runnable mUpdateRunnable = new Runnable() {
         @Override
         public void run() {
-            loadInstalledServices();
             updateServicesPreferences();
         }
     };
@@ -162,7 +161,6 @@
             new SettingsContentObserver(mHandler) {
                 @Override
                 public void onChange(boolean selfChange, Uri uri) {
-                    loadInstalledServices();
                     updateServicesPreferences();
                 }
             };
@@ -218,7 +216,6 @@
     @Override
     public void onResume() {
         super.onResume();
-        loadInstalledServices();
         updateAllPreferences();
 
         mSettingsPackageMonitor.register(getActivity(), getActivity().getMainLooper(), false);
@@ -624,27 +621,6 @@
         }
     }
 
-    private void loadInstalledServices() {
-        Set<ComponentName> installedServices = sInstalledServices;
-        installedServices.clear();
-
-        List<AccessibilityServiceInfo> installedServiceInfos =
-                AccessibilityManager.getInstance(getActivity())
-                        .getInstalledAccessibilityServiceList();
-        if (installedServiceInfos == null) {
-            return;
-        }
-
-        final int installedServiceInfoCount = installedServiceInfos.size();
-        for (int i = 0; i < installedServiceInfoCount; i++) {
-            ResolveInfo resolveInfo = installedServiceInfos.get(i).getResolveInfo();
-            ComponentName installedService = new ComponentName(
-                    resolveInfo.serviceInfo.packageName,
-                    resolveInfo.serviceInfo.name);
-            installedServices.add(installedService);
-        }
-    }
-
     public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
             new BaseSearchIndexProvider() {
         @Override
diff --git a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
index e7896e4..c19e220 100644
--- a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
@@ -49,10 +49,7 @@
 import com.android.settings.widget.ToggleSwitch.OnBeforeCheckedChangeListener;
 import com.android.settingslib.accessibility.AccessibilityUtils;
 
-import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 
 public class ToggleAccessibilityServicePreferenceFragment
         extends ToggleFeaturePreferenceFragment implements DialogInterface.OnClickListener {
@@ -102,56 +99,8 @@
 
     @Override
     public void onPreferenceToggled(String preferenceKey, boolean enabled) {
-        // Parse the enabled services.
-        Set<ComponentName> enabledServices = AccessibilityUtils.getEnabledServicesFromSettings(
-                getActivity());
-
-        if (enabledServices == (Set<?>) Collections.emptySet()) {
-            enabledServices = new HashSet<ComponentName>();
-        }
-
-        // Determine enabled services and accessibility state.
         ComponentName toggledService = ComponentName.unflattenFromString(preferenceKey);
-        boolean accessibilityEnabled = false;
-        if (enabled) {
-            enabledServices.add(toggledService);
-            // Enabling at least one service enables accessibility.
-            accessibilityEnabled = true;
-        } else {
-            enabledServices.remove(toggledService);
-            // Check how many enabled and installed services are present.
-            Set<ComponentName> installedServices = AccessibilitySettings.sInstalledServices;
-            for (ComponentName enabledService : enabledServices) {
-                if (installedServices.contains(enabledService)) {
-                    // Disabling the last service disables accessibility.
-                    accessibilityEnabled = true;
-                    break;
-                }
-            }
-        }
-
-        // Update the enabled services setting.
-        StringBuilder enabledServicesBuilder = new StringBuilder();
-        // Keep the enabled services even if they are not installed since we
-        // have no way to know whether the application restore process has
-        // completed. In general the system should be responsible for the
-        // clean up not settings.
-        for (ComponentName enabledService : enabledServices) {
-            enabledServicesBuilder.append(enabledService.flattenToString());
-            enabledServicesBuilder.append(
-                    AccessibilityUtils.ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR);
-        }
-        final int enabledServicesBuilderLength = enabledServicesBuilder.length();
-        if (enabledServicesBuilderLength > 0) {
-            enabledServicesBuilder.deleteCharAt(enabledServicesBuilderLength - 1);
-        }
-        Settings.Secure.putString(getContentResolver(),
-                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
-                enabledServicesBuilder.toString());
-
-        // Update accessibility enabled.
-        Settings.Secure.putInt(getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_ENABLED, accessibilityEnabled ? 1 : 0);
+        AccessibilityUtils.setAccessibilityServiceState(getActivity(), toggledService, enabled);
     }
 
     // IMPORTANT: Refresh the info since there are dynamically changing