Merge "Fixing Wifi strings and pref ordering per ui"
diff --git a/res/layout/preference_tts_engine.xml b/res/layout/preference_tts_engine.xml
new file mode 100644
index 0000000..3cbdff4
--- /dev/null
+++ b/res/layout/preference_tts_engine.xml
@@ -0,0 +1,89 @@
+<?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:minHeight="?android:attr/listPreferredItemHeight"
+    android:gravity="center_vertical">
+    <LinearLayout
+        android:id="@+id/tts_engine_pref"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:gravity="center_vertical"
+        android:clickable="true"
+        android:focusable="true"
+        android:background="?android:attr/selectableItemBackground">
+        <RadioButton
+            android:id="@+id/tts_engine_radiobutton"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_marginLeft="10dip"
+            android:layout_marginRight="4dip"
+            android:layout_gravity="center_vertical"
+            android:orientation="vertical"
+            android:clickable="true" />
+        <RelativeLayout
+            android:id="@+id/tts_engine_pref_text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="15dip"
+            android:layout_marginRight="6dip"
+            android:layout_marginTop="6dip"
+            android:layout_marginBottom="6dip"
+            android:layout_weight="1">
+            <TextView
+                android:id="@android:id/title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:textAppearance="?android:attr/textAppearanceMedium"
+                android:ellipsize="marquee"
+                android:fadingEdge="horizontal"/>
+            <TextView
+                android:id="@android:id/summary"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_below="@android:id/title"
+                android:layout_alignLeft="@android:id/title"
+                android:visibility="gone"
+                android:textAppearance="?android:attr/textAppearanceSmall"
+                android:textSize="13sp"
+                android:textColor="?android:attr/textColorSecondary"
+                android:maxLines="4" />
+        </RelativeLayout>
+    </LinearLayout>
+    <View
+        android:layout_width="2dip"
+        android:layout_height="match_parent"
+        android:layout_marginTop="5dip"
+        android:layout_marginBottom="5dip"
+        android:background="@android:drawable/divider_horizontal_dark" />
+    <ImageView
+        android:id="@+id/tts_engine_settings"
+        android:layout_width="wrap_content"
+        android:layout_height="fill_parent"
+        android:paddingLeft="15dip"
+        android:paddingRight="?android:attr/scrollbarSize"
+        android:src="@drawable/ic_sysbar_quicksettings"
+        android:contentDescription="@string/tts_engine_settings_button"
+        android:layout_gravity="center"
+        android:clickable="true"
+        android:focusable="true"
+        android:background="?android:attr/selectableItemBackground" />
+</LinearLayout>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 9a84845..3cd367f 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -201,40 +201,20 @@
         <item>150</item>
     </string-array>
 
-    <!-- Default language choices -->
-    <string-array name="tts_lang_entries">
-        <item>American English</item>
-        <item>British English</item>
-        <item>French</item>
-        <item>German</item>
-        <item>Italian</item>
-        <item>Spanish</item>
-    </string-array>
     <!-- Do not translate. -->
-    <string-array name="tts_lang_values">
-        <item>eng-USA</item>
-        <item>eng-GBR</item>
-        <item>fra-FRA</item>
-        <item>deu-DEU</item>
-        <item>ita-ITA</item>
-        <item>spa-ESP</item>
-    </string-array>
-    <!-- Do not translate. -->
-    <string-array name="tts_demo_strings">
-        <item>This is an example of speech synthesis in English.</item>
+    <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>
     </string-array>
-    <!-- Do not translate. -->
-    <string-array name="tts_engine_entries">
-        <item>Pico TTS</item>
-    </string-array>
-    <!-- Do not translate. -->
-    <string-array name="tts_engine_values">
-        <item>com.svox.pico</item>
+    <string-array name="tts_demo_string_langs" translatable="false">
+        <item>eng</item>
+        <item>fra</item>
+        <item>deu</item>
+        <item>ita</item>
+        <item>esp</item>
     </string-array>
 
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 88c9a06..296f5d8 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2980,8 +2980,6 @@
     <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 for demonstration purposes -->
-    <string name="tts_demo">This is an example of speech synthesis.</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 -->
@@ -3028,6 +3026,15 @@
          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>
@@ -3602,7 +3609,7 @@
     <string name="trusted_credentials_remove_confirmation">Permanently remove the user CA certificate?</string>
 
     <!-- Title for the touch exploration tutorial. [CHAR LIMIT=40] -->
-    <string name="accessibility_tutorial_title">Talk As I Touch tutorial</string>
+    <string name="accessibility_tutorial_title">Accessibility tutorial</string>
     <!-- Button label to go to the next touch exploration tutorial lesson. [CHAR LIMIT=10] -->
     <string name="accessibility_tutorial_next">Next</string>
     <!-- Button label to go back to the previous touch explorationtutorial lesson. [CHAR LIMIT=10] -->
@@ -3614,8 +3621,8 @@
 
     <!-- Title for touch exploration tutorial lesson 1. -->
     <string name="accessibility_tutorial_lesson_1_title">Lesson 1: Exploring the screen</string>
-    <!-- Instruction for touch exploration tutorial lesson 1. -->
-    <string name="accessibility_tutorial_lesson_1_text_1">After you turn on Talk As I Touch, you can touch the screen to hear a description of what’s under your finger. For example, the current screen contains application icons. Find one of them by touching the screen and sliding your finger around.</string>
+    <!-- Instruction for touch exploration tutorial lesson 1. "Explore by touch" should match the string for "Title for accessibility preference to enable touch exploration mode." -->
+    <string name="accessibility_tutorial_lesson_1_text_1">After you turn on \"Explore by touch,\" you can touch the screen to learn what’s under your finger. For example, the current screen contains application icons. Find one of them by touching the screen and sliding your finger around.</string>
     <!-- Instruction for touch exploration tutorial lesson 1, displayed after the user touches one icon. -->
     <string name="accessibility_tutorial_lesson_1_text_2_more">Good. Keep sliding your finger around the screen until you find at least one more icon.</string>
     <!-- Instruction for touch exploration tutorial lesson 1, displayed after the user touches a second icon. -->
@@ -3638,7 +3645,7 @@
     <!-- Instruction for touch exploration tutorial lesson 2, displayed after the user scrolls a small amount. -->
     <string name="accessibility_tutorial_lesson_2_text_3_more">Good. Keep sliding your fingers up to scroll some more.</string>
     <!-- Instruction for touch exploration tutorial lesson 2, displayed after the user has scrolled a large amount. -->
-    <string name="accessibility_tutorial_lesson_2_text_4">You have completed the tutorial. To exit and return to the Talk As I Touch setting, find and tap the <xliff:g id="finish" example="Finish">%s</xliff:g> button.</string>
+    <string name="accessibility_tutorial_lesson_2_text_4">You have completed the tutorial. To exit, find and tap the <xliff:g id="finish" example="Finish">%s</xliff:g> button.</string>
 
     <!--  Title for spelling correction settings -->
     <string name="spellcheckers_settings_title">Spelling correction</string>
diff --git a/res/xml/language_settings.xml b/res/xml/language_settings.xml
index f696187..1598939 100644
--- a/res/xml/language_settings.xml
+++ b/res/xml/language_settings.xml
@@ -83,7 +83,7 @@
             android:title="@string/voice_output_category" >
 
         <PreferenceScreen android:key="tts_settings"
-                android:fragment="com.android.settings.TextToSpeechSettings"
+                android:fragment="com.android.settings.tts.TextToSpeechSettings"
                 android:title="@string/tts_settings_title" />
     </PreferenceCategory>
 
diff --git a/res/xml/tts_engine_settings.xml b/res/xml/tts_engine_settings.xml
new file mode 100644
index 0000000..03414e8
--- /dev/null
+++ b/res/xml/tts_engine_settings.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" android:title="">
+    <ListPreference
+        android:key="tts_default_lang"
+        android:title="@string/tts_default_lang_title"
+        android:summary="@string/tts_default_lang_summary"
+        android:persistent="false" />
+
+    <Preference
+        android:key="tts_engine_settings"
+        android:persistent="false"
+        android:title="@string/tts_engine_settings_title" />
+
+    <Preference
+        android:key="tts_install_data"
+        android:persistent="false"
+        android:title="@string/tts_install_data_title"
+        android:summary="@string/tts_install_data_summary" />
+</PreferenceScreen>
diff --git a/res/xml/tts_settings.xml b/res/xml/tts_settings.xml
index ecccc10..2b145d1 100644
--- a/res/xml/tts_settings.xml
+++ b/res/xml/tts_settings.xml
@@ -17,53 +17,24 @@
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
         android:title="@string/tts_settings_title">
 
-        <Preference
-            android:key="tts_play_example"
+    <!-- The contents of this category are filled in by the Java code
+         based on the list of available engines. -->
+    <PreferenceCategory android:key="tts_engine_preference_section"
+        android:title="@string/tts_engine_preference_section_title" />
+
+    <PreferenceCategory android:key="tts_general_section"
+         android:title="@string/tts_general_section_title">
+        <ListPreference
+            android:key="tts_default_rate"
+            android:title="@string/tts_default_rate_title"
+            android:summary="@string/tts_default_rate_summary"
             android:persistent="false"
-            android:title="@string/tts_play_example_title"
-            android:summary="@string/tts_play_example_summary" />
+            android:entries="@array/tts_rate_entries"
+            android:entryValues="@array/tts_rate_values" />
+    </PreferenceCategory>
 
-        <PreferenceCategory
-            android:title="@string/tts_default_settings_section">
-            <ListPreference
-                android:key="tts_default_synth"
-                android:title="@string/tts_default_synth_title"
-                android:summary="@string/tts_default_synth_summary"
-                android:persistent="false"
-                android:entries="@array/tts_engine_entries"
-                android:entryValues="@array/tts_engine_values" />
-
-            <ListPreference
-                android:key="tts_default_rate"
-                android:title="@string/tts_default_rate_title"
-                android:summary="@string/tts_default_rate_summary"
-                android:persistent="false"
-                android:entries="@array/tts_rate_entries"
-                android:entryValues="@array/tts_rate_values" />
-
-            <ListPreference
-                android:key="tts_default_lang"
-                android:title="@string/tts_default_lang_title"
-                android:summary="@string/tts_default_lang_summary"
-                android:persistent="false"
-                android:entries="@array/tts_lang_entries"
-                android:entryValues="@array/tts_lang_values" />
-
-        </PreferenceCategory>
-
-        <PreferenceCategory android:key="tts_engine_settings_section"
-            android:title="@string/tts_engine_settings_section">
-            <Preference
-                android:key="tts_engine_settings"
-                android:persistent="false"
-                android:title="@string/tts_engine_settings_title" />
-
-            <Preference
-                android:key="tts_install_data"
-                android:persistent="false"
-                android:title="@string/tts_install_data_title"
-                android:summary="@string/tts_install_data_summary" />
-       </PreferenceCategory>
-
-
+    <Preference android:key="tts_play_example"
+         android:persistent="false"
+         android:title="@string/tts_play_example_title"
+         android:summary="@string/tts_play_example_summary" />
 </PreferenceScreen>
diff --git a/src/com/android/settings/ChooseLockGeneric.java b/src/com/android/settings/ChooseLockGeneric.java
index 8311c4a..b1bc856 100644
--- a/src/com/android/settings/ChooseLockGeneric.java
+++ b/src/com/android/settings/ChooseLockGeneric.java
@@ -16,8 +16,6 @@
 
 package com.android.settings;
 
-import com.android.internal.widget.LockPatternUtils;
-
 import android.app.Activity;
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
@@ -29,6 +27,8 @@
 import android.preference.PreferenceScreen;
 import android.security.KeyStore;
 
+import com.android.internal.widget.LockPatternUtils;
+
 public class ChooseLockGeneric extends PreferenceActivity {
 
     @Override
diff --git a/src/com/android/settings/SettingsPreferenceFragment.java b/src/com/android/settings/SettingsPreferenceFragment.java
index bd9e331..f7e3b02 100644
--- a/src/com/android/settings/SettingsPreferenceFragment.java
+++ b/src/com/android/settings/SettingsPreferenceFragment.java
@@ -16,28 +16,22 @@
 
 package com.android.settings;
 
-import android.app.Activity;
 import android.app.Dialog;
 import android.app.DialogFragment;
 import android.app.Fragment;
 import android.content.ContentResolver;
 import android.content.DialogInterface;
-import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceFragment;
-import android.text.TextUtils;
 import android.util.Log;
-import android.view.View;
-import android.view.View.OnClickListener;
 import android.widget.Button;
 
 /**
  * Base class for Settings fragments, with some helper functions and dialog management.
  */
-public class SettingsPreferenceFragment extends PreferenceFragment
-        implements DialogCreatable {
+public class SettingsPreferenceFragment extends PreferenceFragment implements DialogCreatable {
 
     private static final String TAG = "SettingsPreferenceFragment";
 
@@ -241,8 +235,8 @@
             Fragment caller, String fragmentClass, int requestCode, Bundle extras) {
         if (getActivity() instanceof PreferenceActivity) {
             PreferenceActivity preferenceActivity = (PreferenceActivity)getActivity();
-            preferenceActivity.startPreferencePanel(fragmentClass, extras, 0, null, caller,
-                    requestCode);
+            preferenceActivity.startPreferencePanel(fragmentClass, extras,
+                    R.string.lock_settings_picker_title, null, caller, requestCode);
             return true;
         } else {
             Log.w(TAG, "Parent isn't PreferenceActivity, thus there's no way to launch the "
diff --git a/src/com/android/settings/TextToSpeechSettings.java b/src/com/android/settings/TextToSpeechSettings.java
deleted file mode 100644
index d76f08f..0000000
--- a/src/com/android/settings/TextToSpeechSettings.java
+++ /dev/null
@@ -1,709 +0,0 @@
-/*
- * Copyright (C) 2009 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 static android.provider.Settings.Secure.TTS_DEFAULT_COUNTRY;
-import static android.provider.Settings.Secure.TTS_DEFAULT_LANG;
-import static android.provider.Settings.Secure.TTS_DEFAULT_RATE;
-import static android.provider.Settings.Secure.TTS_DEFAULT_SYNTH;
-import static android.provider.Settings.Secure.TTS_DEFAULT_VARIANT;
-import static android.provider.Settings.Secure.TTS_USE_DEFAULTS;
-
-import android.app.AlertDialog;
-import android.content.ActivityNotFoundException;
-import android.content.ContentResolver;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.os.Bundle;
-import android.preference.ListPreference;
-import android.preference.Preference;
-import android.preference.Preference.OnPreferenceClickListener;
-import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
-import android.speech.tts.TextToSpeech;
-import android.speech.tts.TextToSpeech.EngineInfo;
-import android.speech.tts.TtsEngines;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-import java.util.StringTokenizer;
-
-public class TextToSpeechSettings extends SettingsPreferenceFragment implements
-        Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener,
-        TextToSpeech.OnInitListener {
-
-    private static final String TAG = "TextToSpeechSettings";
-
-    private static final String KEY_TTS_PLAY_EXAMPLE = "tts_play_example";
-    private static final String KEY_TTS_INSTALL_DATA = "tts_install_data";
-    private static final String KEY_TTS_USE_DEFAULT = "toggle_use_default_tts_settings";
-    private static final String KEY_TTS_DEFAULT_RATE = "tts_default_rate";
-    private static final String KEY_TTS_DEFAULT_LANG = "tts_default_lang";
-    private static final String KEY_TTS_DEFAULT_COUNTRY = "tts_default_country";
-    private static final String KEY_TTS_DEFAULT_VARIANT = "tts_default_variant";
-    private static final String KEY_TTS_DEFAULT_SYNTH = "tts_default_synth";
-    private static final String KEY_TTS_ENGINE_SETTINGS = "tts_engine_settings";
-
-    private static final String KEY_PLUGIN_ENABLED_PREFIX = "ENABLED_";
-    private static final String KEY_PLUGIN_SETTINGS_PREFIX = "SETTINGS_";
-
-    // TODO move default Locale values to TextToSpeech.Engine
-    private static final String DEFAULT_LANG_VAL = "eng";
-    private static final String DEFAULT_COUNTRY_VAL = "USA";
-    private static final String DEFAULT_VARIANT_VAL = "";
-
-    private static final String LOCALE_DELIMITER = "-";
-
-    private Preference mPlayExample = null;
-
-    private ListPreference mDefaultRatePref = null;
-    private ListPreference mDefaultLocPref = null;
-    private ListPreference mDefaultSynthPref = null;
-
-    private Preference mInstallData = null;
-    private Preference mEngineSettings = null;
-
-    private String             mDefaultLanguage = null;
-    private String             mDefaultCountry = null;
-    private String             mDefaultLocVariant = null;
-    private int                mDefaultRate = TextToSpeech.Engine.DEFAULT_RATE;
-
-    // Index of the current string to use for the demo.
-    private int      mDemoStringIndex = 0;
-
-    private boolean mEnableDemo = false;
-    private boolean mVoicesMissing = false;
-
-    private TextToSpeech mTts = null;
-    private TtsEngines mEnginesHelper = null;
-    private boolean mTtsStarted = false;
-
-    /**
-     * Request code (arbitrary value) for voice data check through
-     * startActivityForResult.
-     */
-    private static final int VOICE_DATA_INTEGRITY_CHECK = 1977;
-    private static final int GET_SAMPLE_TEXT = 1983;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        addPreferencesFromResource(R.xml.tts_settings);
-
-        getActivity().setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
-
-        mEnableDemo = false;
-        mTtsStarted = false;
-
-        Locale currentLocale = Locale.getDefault();
-        mDefaultLanguage = currentLocale.getISO3Language();
-        mDefaultCountry = currentLocale.getISO3Country();
-        mDefaultLocVariant = currentLocale.getVariant();
-
-        mPlayExample = findPreference(KEY_TTS_PLAY_EXAMPLE);
-        mPlayExample.setOnPreferenceClickListener(this);
-
-        mInstallData = findPreference(KEY_TTS_INSTALL_DATA);
-        mInstallData.setOnPreferenceClickListener(this);
-
-        mDefaultSynthPref = (ListPreference) findPreference(KEY_TTS_DEFAULT_SYNTH);
-        mDefaultRatePref = (ListPreference) findPreference(KEY_TTS_DEFAULT_RATE);
-        mDefaultLocPref = (ListPreference) findPreference(KEY_TTS_DEFAULT_LANG);
-
-        mEngineSettings = findPreference(KEY_TTS_ENGINE_SETTINGS);
-        mEngineSettings.setEnabled(false);
-
-        mTts = new TextToSpeech(getActivity().getApplicationContext(), this);
-        mEnginesHelper = new TtsEngines(getActivity().getApplicationContext());
-
-        initDefaultSettings();
-        initEngineSpecificSettings();
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        if (mTtsStarted){
-            // whenever we return to this screen, we don't know the state of the
-            // system, so we have to recheck that we can play the demo, or it must be disabled.
-            // TODO make the TTS service listen to "changes in the system", i.e. sd card un/mount
-            updateWidgetState();
-            checkVoiceData();
-        }
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        if (mTts != null) {
-            mTts.shutdown();
-        }
-    }
-
-    @Override
-    public void onPause() {
-        super.onPause();
-        if ((mDefaultRatePref != null) && (mDefaultRatePref.getDialog() != null)) {
-            mDefaultRatePref.getDialog().dismiss();
-        }
-        if ((mDefaultLocPref != null) && (mDefaultLocPref.getDialog() != null)) {
-            mDefaultLocPref.getDialog().dismiss();
-        }
-        if ((mDefaultSynthPref != null) && (mDefaultSynthPref.getDialog() != null)) {
-            mDefaultSynthPref.getDialog().dismiss();
-        }
-    }
-
-    private void initEngineSpecificSettings() {
-        final String engineName = mEnginesHelper.getDefaultEngine();
-        final EngineInfo engine = mEnginesHelper.getEngineInfo(engineName);
-
-        mEngineSettings.setTitle(getResources().getString(R.string.tts_engine_settings_title,
-                engine.label));
-
-        final Intent settingsIntent = mEnginesHelper.getSettingsIntent(engineName);
-        if (settingsIntent != null) {
-            mEngineSettings.setOnPreferenceClickListener(new OnPreferenceClickListener() {
-                public boolean onPreferenceClick(Preference preference) {
-                    startActivity(settingsIntent);
-                    return true;
-                }
-            });
-            mEngineSettings.setEnabled(true);
-        } else {
-            mEngineSettings.setEnabled(false);
-        }
-
-    }
-
-    private void initDefaultSettings() {
-        ContentResolver resolver = getContentResolver();
-
-        // Find the default TTS values in the settings, initialize and store the
-        // settings if they are not found.
-
-        // Default synthesis engine
-        loadEngines();
-        mDefaultSynthPref.setOnPreferenceChangeListener(this);
-
-        // Default rate
-        try {
-            mDefaultRate = Settings.Secure.getInt(resolver, TTS_DEFAULT_RATE);
-        } catch (SettingNotFoundException e) {
-            // default rate setting not found, initialize it
-            mDefaultRate = TextToSpeech.Engine.DEFAULT_RATE;
-            Settings.Secure.putInt(resolver, TTS_DEFAULT_RATE, mDefaultRate);
-        }
-        mDefaultRatePref.setValue(String.valueOf(mDefaultRate));
-        mDefaultRatePref.setOnPreferenceChangeListener(this);
-
-        // Default language / country / variant : these three values map to a single ListPref
-        // representing the matching Locale
-        initDefaultLang();
-        mDefaultLocPref.setOnPreferenceChangeListener(this);
-    }
-
-    /**
-     * Ask the current default engine to launch the matching CHECK_TTS_DATA activity
-     * to check the required TTS files are properly installed.
-     */
-    private void checkVoiceData() {
-        String defaultEngine = mTts.getDefaultEngine();
-        if (TextUtils.isEmpty(defaultEngine)) return;
-        Intent intent = new Intent(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
-        intent.setPackage(defaultEngine);
-        try {
-            Log.v(TAG, "Checking voice data: " + intent.toUri(0));
-            startActivityForResult(intent, VOICE_DATA_INTEGRITY_CHECK);
-        } catch (ActivityNotFoundException ex) {
-            Log.e(TAG, "Failed to check TTS data, no acitivty found for " + intent + ")");
-        }
-    }
-
-
-    /**
-     * Ask the current default engine to launch the matching INSTALL_TTS_DATA activity
-     * so the required TTS files are properly installed.
-     */
-    private void installVoiceData() {
-        String defaultEngine = mTts.getDefaultEngine();
-        if (TextUtils.isEmpty(defaultEngine)) return;
-        Intent intent = new Intent(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.setPackage(defaultEngine);
-        try {
-            Log.v(TAG, "Installing voice data: " + intent.toUri(0));
-            startActivity(intent);
-        } catch (ActivityNotFoundException ex) {
-            Log.e(TAG, "Failed to install TTS data, no acitivty found for " + intent + ")");
-        }
-    }
-
-    /**
-     * Ask the current default engine to return a string of sample text to be
-     * spoken to the user.
-     */
-    private void getSampleText() {
-        String defaultEngine = mTts.getDefaultEngine();
-        if (TextUtils.isEmpty(defaultEngine)) return;
-        Intent intent = new Intent(TextToSpeech.Engine.ACTION_GET_SAMPLE_TEXT);
-        intent.putExtra("language", mDefaultLanguage);
-        intent.putExtra("country", mDefaultCountry);
-        intent.putExtra("variant", mDefaultLocVariant);
-        intent.setPackage(defaultEngine);
-
-        try {
-            Log.v(TAG, "Getting sample text: " + intent.toUri(0));
-            startActivityForResult(intent, GET_SAMPLE_TEXT);
-        } catch (ActivityNotFoundException ex) {
-            Log.e(TAG, "Failed to get sample text, no acitivty found for " + intent + ")");
-        }
-    }
-
-    /**
-     * Called when the TTS engine is initialized.
-     */
-    public void onInit(int status) {
-        if (status == TextToSpeech.SUCCESS) {
-            mEnableDemo = true;
-            if (mDefaultLanguage == null) {
-                mDefaultLanguage = Locale.getDefault().getISO3Language();
-            }
-            if (mDefaultCountry == null) {
-                mDefaultCountry = Locale.getDefault().getISO3Country();
-            }
-            if (mDefaultLocVariant == null) {
-                mDefaultLocVariant = new String();
-            }
-            mTts.setLanguage(new Locale(mDefaultLanguage, mDefaultCountry, mDefaultLocVariant));
-            updateWidgetState();
-            checkVoiceData();
-            mTtsStarted = true;
-            Log.v(TAG, "TTS engine for settings screen initialized.");
-        } else {
-            Log.v(TAG, "TTS engine for settings screen failed to initialize successfully.");
-            mEnableDemo = false;
-        }
-        updateWidgetState();
-    }
-
-    /**
-     * Called when voice data integrity check returns
-     */
-    @Override
-    public void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (requestCode == VOICE_DATA_INTEGRITY_CHECK) {
-            onVoiceDataIntegrityCheckDone(data);
-        } else if (requestCode == GET_SAMPLE_TEXT) {
-            onSampleTextReceived(resultCode, data);
-        }
-    }
-
-    private void onVoiceDataIntegrityCheckDone(Intent data) {
-        if (data == null){
-            Log.e(TAG, "TTS data check failed data = null");
-            // The CHECK_TTS_DATA activity for the plugin did not run properly;
-            // disable the preview and install controls and return.
-            mEnableDemo = false;
-            mVoicesMissing = false;
-            updateWidgetState();
-            return;
-        }
-        Log.v(TAG, "TTS data check completed, data = " + data.toUri(0));
-        ArrayList<String> available =
-                data.getStringArrayListExtra(TextToSpeech.Engine.EXTRA_AVAILABLE_VOICES);
-        ArrayList<String> unavailable =
-                data.getStringArrayListExtra(TextToSpeech.Engine.EXTRA_UNAVAILABLE_VOICES);
-        if (available == null || unavailable == null){
-            Log.e(TAG, "TTS data check failed (available == == null)");
-            // The CHECK_TTS_DATA activity for the plugin did not run properly;
-            // disable the preview and install controls and return.
-            mEnableDemo = false;
-            mVoicesMissing = false;
-            updateWidgetState();
-            return;
-        }
-        if (available.size() > 0){
-            if (mTts == null) {
-                mTts = new TextToSpeech(getActivity(), this);
-            }
-
-            updateDefaultLocPref(available);
-
-            mEnableDemo = true;
-            // Make sure that the default language can be used.
-            int languageResult = mTts.setLanguage(
-                    new Locale(mDefaultLanguage, mDefaultCountry, mDefaultLocVariant));
-            if (languageResult < TextToSpeech.LANG_AVAILABLE){
-                Locale currentLocale = Locale.getDefault();
-                mDefaultLanguage = currentLocale.getISO3Language();
-                mDefaultCountry = currentLocale.getISO3Country();
-                mDefaultLocVariant = currentLocale.getVariant();
-                languageResult = mTts.setLanguage(
-                        new Locale(mDefaultLanguage, mDefaultCountry, mDefaultLocVariant));
-                // If the default Locale isn't supported, just choose the first available
-                // language so that there is at least something.
-                if (languageResult < TextToSpeech.LANG_AVAILABLE){
-                    parseLocaleInfo(mDefaultLocPref.getEntryValues()[0].toString());
-                    mTts.setLanguage(
-                            new Locale(mDefaultLanguage, mDefaultCountry, mDefaultLocVariant));
-                }
-                ContentResolver resolver = getContentResolver();
-                Settings.Secure.putString(resolver, TTS_DEFAULT_LANG, mDefaultLanguage);
-                Settings.Secure.putString(resolver, TTS_DEFAULT_COUNTRY, mDefaultCountry);
-                Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, mDefaultLocVariant);
-            }
-        } else {
-            mEnableDemo = false;
-        }
-
-        if (unavailable.size() > 0){
-            mVoicesMissing = true;
-        } else {
-            mVoicesMissing = false;
-        }
-
-        updateWidgetState();
-    }
-
-    private void updateDefaultLocPref(ArrayList<String> availableLangs) {
-        CharSequence[] entries = new CharSequence[availableLangs.size()];
-        CharSequence[] entryValues = new CharSequence[availableLangs.size()];
-        int selectedLanguageIndex = -1;
-        String selectedLanguagePref = mDefaultLanguage;
-        if (mDefaultCountry.length() > 0) {
-            selectedLanguagePref = selectedLanguagePref + LOCALE_DELIMITER +
-                    mDefaultCountry;
-        }
-        if (mDefaultLocVariant.length() > 0) {
-            selectedLanguagePref = selectedLanguagePref + LOCALE_DELIMITER +
-                    mDefaultLocVariant;
-        }
-        for (int i = 0; i < availableLangs.size(); i++) {
-            String[] langCountryVariant = availableLangs.get(i).split("-");
-            Locale loc = null;
-            if (langCountryVariant.length == 1){
-                loc = new Locale(langCountryVariant[0]);
-            } else if (langCountryVariant.length == 2){
-                loc = new Locale(langCountryVariant[0], langCountryVariant[1]);
-            } else if (langCountryVariant.length == 3){
-                loc = new Locale(langCountryVariant[0], langCountryVariant[1],
-                                 langCountryVariant[2]);
-            }
-            if (loc != null){
-                entries[i] = loc.getDisplayName();
-                entryValues[i] = availableLangs.get(i);
-                if (entryValues[i].equals(selectedLanguagePref)) {
-                    selectedLanguageIndex = i;
-                }
-            }
-        }
-        mDefaultLocPref.setEntries(entries);
-        mDefaultLocPref.setEntryValues(entryValues);
-        if (selectedLanguageIndex > -1) {
-            mDefaultLocPref.setValueIndex(selectedLanguageIndex);
-        }
-    }
-
-    private void onSampleTextReceived(int resultCode, Intent data) {
-        if (resultCode == TextToSpeech.LANG_AVAILABLE) {
-            String sample = getActivity().getString(R.string.tts_demo);
-            if (data != null && data.getStringExtra("sampleText") != null) {
-                sample = data.getStringExtra("sampleText");
-            }
-            Log.v(TAG, "Got sample text: " + sample);
-            if (mTts != null) {
-                mTts.speak(sample, TextToSpeech.QUEUE_FLUSH, null);
-            }
-        } else {
-            // TODO: Display an error here to the user.
-            Log.e(TAG, "Did not have a sample string for the requested language");
-        }
-    }
-
-    public boolean onPreferenceChange(Preference preference, Object objValue) {
-        if (KEY_TTS_USE_DEFAULT.equals(preference.getKey())) {
-            // "Use Defaults"
-            int value = ((Boolean) objValue) ? 1 : 0;
-            Settings.Secure.putInt(getContentResolver(), TTS_USE_DEFAULTS, value);
-            Log.i(TAG, "TTS 'use default' settings changed, now " + value);
-        } else if (KEY_TTS_DEFAULT_RATE.equals(preference.getKey())) {
-            // Default rate
-            mDefaultRate = Integer.parseInt((String) objValue);
-            try {
-                Settings.Secure.putInt(getContentResolver(), TTS_DEFAULT_RATE, mDefaultRate);
-                if (mTts != null) {
-                    mTts.setSpeechRate(mDefaultRate / 100.0f);
-                }
-                Log.v(TAG, "TTS default rate changed, now " + mDefaultRate);
-            } catch (NumberFormatException e) {
-                Log.e(TAG, "could not persist default TTS rate setting", e);
-            }
-        } else if (KEY_TTS_DEFAULT_LANG.equals(preference.getKey())) {
-            // Default locale
-            ContentResolver resolver = getContentResolver();
-            parseLocaleInfo((String) objValue);
-            Settings.Secure.putString(resolver, TTS_DEFAULT_LANG, mDefaultLanguage);
-            Settings.Secure.putString(resolver, TTS_DEFAULT_COUNTRY, mDefaultCountry);
-            Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, mDefaultLocVariant);
-            Log.v(TAG, "TTS default lang/country/variant set to "
-                    + mDefaultLanguage + "/" + mDefaultCountry + "/" + mDefaultLocVariant);
-            if (mTts != null) {
-                mTts.setLanguage(new Locale(mDefaultLanguage, mDefaultCountry, mDefaultLocVariant));
-            }
-            int newIndex = mDefaultLocPref.findIndexOfValue((String)objValue);
-            Log.v(TAG, " selected is " + newIndex);
-            mDemoStringIndex = newIndex > -1 ? newIndex : 0;
-        } else if (KEY_TTS_DEFAULT_SYNTH.equals(preference.getKey())) {
-            final String name = objValue.toString();
-            final EngineInfo info = mEnginesHelper.getEngineInfo(name);
-
-            if (info.system) {
-                // For system engines, do away with the alert dialog.
-                updateDefaultEngine(name);
-                initEngineSpecificSettings();
-            } else {
-                // For all other engines, display a warning message before
-                // turning them on.
-                displayDataAlert(preference, name);
-            }
-
-            // We'll deal with updating the UI ourselves.
-            return false;
-        }
-
-        return true;
-    }
-
-
-    /**
-     * Called when mPlayExample or mInstallData is clicked
-     */
-    public boolean onPreferenceClick(Preference preference) {
-        if (preference == mPlayExample) {
-            // Get the sample text from the TTS engine; onActivityResult will do
-            // the actual speaking
-            getSampleText();
-            return true;
-        } else if (preference == mInstallData) {
-            installVoiceData();
-            // quit this activity so it needs to be restarted after installation of the voice data
-            finish();
-            return true;
-        }
-
-        return false;
-    }
-
-    private void updateWidgetState() {
-        mPlayExample.setEnabled(mEnableDemo);
-        mDefaultRatePref.setEnabled(mEnableDemo);
-        mDefaultLocPref.setEnabled(mEnableDemo);
-
-        mInstallData.setEnabled(mVoicesMissing);
-    }
-
-
-    private void parseLocaleInfo(String locale) {
-        StringTokenizer tokenizer = new StringTokenizer(locale, LOCALE_DELIMITER);
-        mDefaultLanguage = "";
-        mDefaultCountry = "";
-        mDefaultLocVariant = "";
-
-        if (locale != null) {
-            String[] components = locale.split(LOCALE_DELIMITER);
-            if (components.length > 0) {
-                mDefaultLanguage = components[0];
-            }
-            if (components.length > 1) {
-                mDefaultCountry = components[1];
-            }
-            if (components.length > 2) {
-                mDefaultLocVariant = components[2];
-            }
-        }
-    }
-
-
-    /**
-     *  Initialize the default language in the UI and in the preferences.
-     *  After this method has been invoked, the default language is a supported Locale.
-     */
-    private void initDefaultLang() {
-        // if there isn't already a default language preference
-        if (!hasLangPref()) {
-            // if the current Locale is supported
-            if (isCurrentLocSupported()) {
-                // then use the current Locale as the default language
-                useCurrentLocAsDefault();
-            } else {
-                // otherwise use a default supported Locale as the default language
-                useSupportedLocAsDefault();
-            }
-        }
-
-        // Update the language preference list with the default language and the matching
-        // demo string (at this stage there is a default language pref)
-        ContentResolver resolver = getContentResolver();
-        mDefaultLanguage = Settings.Secure.getString(resolver, TTS_DEFAULT_LANG);
-        mDefaultCountry = Settings.Secure.getString(resolver, TTS_DEFAULT_COUNTRY);
-        mDefaultLocVariant = Settings.Secure.getString(resolver, TTS_DEFAULT_VARIANT);
-
-        // update the demo string
-        mDemoStringIndex = mDefaultLocPref.findIndexOfValue(mDefaultLanguage + LOCALE_DELIMITER
-                + mDefaultCountry);
-        if (mDemoStringIndex > -1){
-            mDefaultLocPref.setValueIndex(mDemoStringIndex);
-        }
-    }
-
-    /**
-     * (helper function for initDefaultLang() )
-     * Returns whether there is a default language in the TTS settings.
-     */
-    private boolean hasLangPref() {
-        ContentResolver resolver = getContentResolver();
-        String language = Settings.Secure.getString(resolver, TTS_DEFAULT_LANG);
-        if ((language == null) || (language.length() < 1)) {
-            return false;
-        }
-        String country = Settings.Secure.getString(resolver, TTS_DEFAULT_COUNTRY);
-        if (country == null) {
-            return false;
-        }
-        String variant = Settings.Secure.getString(resolver, TTS_DEFAULT_VARIANT);
-        if (variant == null) {
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * (helper function for initDefaultLang() )
-     * Returns whether the current Locale is supported by this Settings screen
-     */
-    private boolean isCurrentLocSupported() {
-        String currentLocID = Locale.getDefault().getISO3Language() + LOCALE_DELIMITER
-                + Locale.getDefault().getISO3Country();
-        return (mDefaultLocPref.findIndexOfValue(currentLocID) > -1);
-    }
-
-    /**
-     * (helper function for initDefaultLang() )
-     * Sets the default language in TTS settings to be the current Locale.
-     * This should only be used after checking that the current Locale is supported.
-     */
-    private void useCurrentLocAsDefault() {
-        Locale currentLocale = Locale.getDefault();
-        ContentResolver resolver = getContentResolver();
-        Settings.Secure.putString(resolver, TTS_DEFAULT_LANG, currentLocale.getISO3Language());
-        Settings.Secure.putString(resolver, TTS_DEFAULT_COUNTRY, currentLocale.getISO3Country());
-        Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, currentLocale.getVariant());
-    }
-
-    /**
-     * (helper function for initDefaultLang() )
-     * Sets the default language in TTS settings to be one known to be supported
-     */
-    private void useSupportedLocAsDefault() {
-        ContentResolver resolver = getContentResolver();
-        Settings.Secure.putString(resolver, TTS_DEFAULT_LANG, DEFAULT_LANG_VAL);
-        Settings.Secure.putString(resolver, TTS_DEFAULT_COUNTRY, DEFAULT_COUNTRY_VAL);
-        Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, DEFAULT_VARIANT_VAL);
-    }
-
-    private void loadEngines() {
-        List<EngineInfo> engines = mEnginesHelper.getEngines();
-        CharSequence entries[] = new CharSequence[engines.size()];
-        CharSequence values[] = new CharSequence[engines.size()];
-
-        final int count = engines.size();
-        for (int i = 0; i < count; ++i) {
-            final EngineInfo engine = engines.get(i);
-            entries[i] = engine.label;
-            values[i] = engine.name;
-        }
-
-        mDefaultSynthPref.setEntries(entries);
-        mDefaultSynthPref.setEntryValues(values);
-
-        // Set the selected engine based on the saved preference
-        String selectedEngine = Settings.Secure.getString(getContentResolver(), TTS_DEFAULT_SYNTH);
-        int selectedEngineIndex = mDefaultSynthPref.findIndexOfValue(selectedEngine);
-        if (selectedEngineIndex == -1){
-            selectedEngineIndex = mDefaultSynthPref.findIndexOfValue(
-                    mEnginesHelper.getHighestRankedEngineName());
-        }
-        if (selectedEngineIndex >= 0) {
-            mDefaultSynthPref.setValueIndex(selectedEngineIndex);
-        }
-    }
-
-    private void displayDataAlert(Preference pref, final String key) {
-        Log.v(TAG, "Displaying data alert for :" + key);
-        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-        builder.setTitle(android.R.string.dialog_alert_title);
-        builder.setIcon(android.R.drawable.ic_dialog_alert);
-        builder.setMessage(getActivity().getString(
-                R.string.tts_engine_security_warning, pref.getTitle()));
-        builder.setCancelable(true);
-        builder.setPositiveButton(android.R.string.ok,
-                new DialogInterface.OnClickListener() {
-                    public void onClick(DialogInterface dialog, int which) {
-                       updateDefaultEngine(key);
-                       loadEngines();
-                       initEngineSpecificSettings();
-                    }
-                });
-        builder.setNegativeButton(android.R.string.cancel, null);
-
-        AlertDialog dialog = builder.create();
-        dialog.show();
-    }
-
-    private void updateDefaultEngine(String engine) {
-        Log.v(TAG, "Updating default synth to : " + engine);
-        if (mTts != null) {
-            try {
-                mTts.shutdown();
-                mTts = null;
-            } catch (Exception e) {
-                Log.e(TAG, "Error shutting down TTS engine" + e);
-            }
-        }
-
-        mTts = new TextToSpeech(getActivity().getApplicationContext(), this, engine);
-        mEnableDemo = false;
-        mVoicesMissing = false;
-
-        // Persist this value to settings and update the UI before we check
-        // voice data because if the TTS class connected without any exception, "engine"
-        // will be the default engine irrespective of whether the voice check
-        // passes or not.
-        Settings.Secure.putString(getContentResolver(), TTS_DEFAULT_SYNTH, engine);
-        mDefaultSynthPref.setValue(engine);
-        updateWidgetState();
-
-        checkVoiceData();
-
-        Log.v(TAG, "The default synth is now: " + engine);
-    }
-
-}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageDetail.java b/src/com/android/settings/fuelgauge/PowerUsageDetail.java
index 7717503..b70312b 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageDetail.java
@@ -44,8 +44,8 @@
 import android.widget.TextView;
 
 import com.android.settings.DisplaySettings;
+import com.android.settings.LocationSettings;
 import com.android.settings.R;
-import com.android.settings.SecuritySettings;
 import com.android.settings.WirelessSettings;
 import com.android.settings.applications.InstalledAppDetails;
 import com.android.settings.bluetooth.BluetoothSettings;
@@ -79,7 +79,7 @@
     public static final int ACTION_BLUETOOTH_SETTINGS = 3;
     public static final int ACTION_WIRELESS_SETTINGS = 4;
     public static final int ACTION_APP_DETAILS = 5;
-    public static final int ACTION_SECURITY_SETTINGS = 6;
+    public static final int ACTION_LOCATION_SETTINGS = 6;
     public static final int ACTION_FORCE_STOP = 7;
     public static final int ACTION_REPORT = 8;
 
@@ -280,9 +280,9 @@
             case ACTION_APP_DETAILS:
                 startApplicationDetailsActivity();
                 break;
-            case ACTION_SECURITY_SETTINGS:
-                pa.startPreferencePanel(SecuritySettings.class.getName(), null,
-                        R.string.security_settings_title, null, null, 0);
+            case ACTION_LOCATION_SETTINGS:
+                pa.startPreferencePanel(LocationSettings.class.getName(), null,
+                        R.string.location_settings_title, null, null, 0);
                 break;
             case ACTION_FORCE_STOP:
                 killProcesses();
@@ -348,8 +348,8 @@
                     // TODO:
                 }
                 if (mUsesGps) {
-                    addControl(R.string.security_settings_title,
-                            R.string.battery_sugg_apps_gps, ACTION_SECURITY_SETTINGS);
+                    addControl(R.string.location_settings_title,
+                            R.string.battery_sugg_apps_gps, ACTION_LOCATION_SETTINGS);
                     removeHeader = false;
                 }
                 break;
diff --git a/src/com/android/settings/tts/TextToSpeechSettings.java b/src/com/android/settings/tts/TextToSpeechSettings.java
new file mode 100644
index 0000000..e8255bf
--- /dev/null
+++ b/src/com/android/settings/tts/TextToSpeechSettings.java
@@ -0,0 +1,495 @@
+/*
+ * 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.tts;
+
+import static android.provider.Settings.Secure.TTS_DEFAULT_RATE;
+import static android.provider.Settings.Secure.TTS_DEFAULT_SYNTH;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.tts.TtsEnginePreference.RadioButtonGroupState;
+
+import android.app.AlertDialog;
+import android.content.ActivityNotFoundException;
+import android.content.ContentResolver;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceCategory;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
+import android.speech.tts.TextToSpeech;
+import android.speech.tts.TextToSpeech.EngineInfo;
+import android.speech.tts.TtsEngines;
+import android.text.TextUtils;
+import android.util.Log;
+import android.widget.Checkable;
+
+import java.util.List;
+import java.util.Locale;
+
+public class TextToSpeechSettings extends SettingsPreferenceFragment implements
+        Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener,
+        RadioButtonGroupState {
+
+    private static final String TAG = "TextToSpeechSettings";
+    private static final boolean DBG = false;
+
+    /** Preference key for the "play TTS example" preference. */
+    private static final String KEY_PLAY_EXAMPLE = "tts_play_example";
+
+    /** Preference key for the TTS rate selection dialog. */
+    private static final String KEY_DEFAULT_RATE = "tts_default_rate";
+
+    /**
+     * Preference key for the engine selection preference.
+     */
+    private static final String KEY_ENGINE_PREFERENCE_SECTION =
+            "tts_engine_preference_section";
+
+    /**
+     * These look like birth years, but they aren't mine. I'm much younger than this.
+     */
+    private static final int GET_SAMPLE_TEXT = 1983;
+    private static final int VOICE_DATA_INTEGRITY_CHECK = 1977;
+
+    private PreferenceCategory mEnginePreferenceCategory;
+    private ListPreference mDefaultRatePref;
+    private Preference mPlayExample;
+
+    private int mDefaultRate = TextToSpeech.Engine.DEFAULT_RATE;
+
+    /**
+     * The currently selected engine.
+     */
+    private String mCurrentEngine;
+
+    /**
+     * The engine checkbox that is currently checked. Saves us a bit of effort
+     * in deducing the right one from the currently selected engine.
+     */
+    private Checkable mCurrentChecked;
+
+    /**
+     * The previously selected TTS engine. Useful for rollbacks if the users
+     * choice is not loaded or fails a voice integrity check.
+     */
+    private String mPreviousEngine;
+
+    private TextToSpeech mTts = null;
+    private TtsEngines mEnginesHelper = null;
+
+    /**
+     * The initialization listener used when we are initalizing the settings
+     * screen for the first time (as opposed to when a user changes his choice
+     * of engine).
+     */
+    private final TextToSpeech.OnInitListener mInitListener = new TextToSpeech.OnInitListener() {
+        @Override
+        public void onInit(int status) {
+            onInitEngine(status);
+        }
+    };
+
+    /**
+     * The initialization listener used when the user changes his choice of
+     * engine (as opposed to when then screen is being initialized for the first
+     * time).
+     */
+    private final TextToSpeech.OnInitListener mUpdateListener = new TextToSpeech.OnInitListener() {
+        @Override
+        public void onInit(int status) {
+            onUpdateEngine(status);
+        }
+    };
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        addPreferencesFromResource(R.xml.tts_settings);
+
+        getActivity().setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
+
+        mPlayExample = findPreference(KEY_PLAY_EXAMPLE);
+        mPlayExample.setOnPreferenceClickListener(this);
+
+        mEnginePreferenceCategory = (PreferenceCategory) findPreference(
+                KEY_ENGINE_PREFERENCE_SECTION);
+        mDefaultRatePref = (ListPreference) findPreference(KEY_DEFAULT_RATE);
+
+        mTts = new TextToSpeech(getActivity().getApplicationContext(), mInitListener);
+        mEnginesHelper = new TtsEngines(getActivity().getApplicationContext());
+
+        initSettings();
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (mTts != null) {
+            mTts.shutdown();
+            mTts = null;
+        }
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        if ((mDefaultRatePref != null) && (mDefaultRatePref.getDialog() != null)) {
+            mDefaultRatePref.getDialog().dismiss();
+        }
+    }
+
+    private void initSettings() {
+        final ContentResolver resolver = getContentResolver();
+
+        // Set up the default rate.
+        try {
+            mDefaultRate = Settings.Secure.getInt(resolver, TTS_DEFAULT_RATE);
+        } catch (SettingNotFoundException e) {
+            // Default rate setting not found, initialize it
+            mDefaultRate = TextToSpeech.Engine.DEFAULT_RATE;
+        }
+        mDefaultRatePref.setValue(String.valueOf(mDefaultRate));
+        mDefaultRatePref.setOnPreferenceChangeListener(this);
+
+        mCurrentEngine = mTts.getCurrentEngine();
+
+        PreferenceActivity preferenceActivity = null;
+        if (getActivity() instanceof PreferenceActivity) {
+            preferenceActivity = (PreferenceActivity) getActivity();
+        } else {
+            throw new IllegalStateException("TextToSpeechSettings used outside a " +
+                    "PreferenceActivity");
+        }
+
+        mEnginePreferenceCategory.removeAll();
+
+        List<EngineInfo> engines = mEnginesHelper.getEngines();
+        for (EngineInfo engine : engines) {
+            TtsEnginePreference enginePref = new TtsEnginePreference(getActivity(), engine,
+                    this, preferenceActivity);
+            mEnginePreferenceCategory.addPreference(enginePref);
+        }
+
+        checkVoiceData(mCurrentEngine);
+    }
+
+    private void maybeUpdateTtsLanguage(String currentEngine) {
+        if (currentEngine != null && mTts != null) {
+            final String localeString = mEnginesHelper.getLocalePrefForEngine(
+                    currentEngine);
+            if (localeString != null) {
+                final String[] locale = TtsEngines.parseLocalePref(localeString);
+
+                if (DBG) Log.d(TAG, "Loading language ahead of sample check : " + locale);
+                mTts.setLanguage(new Locale(locale[0], locale[1], locale[2]));
+            }
+        }
+    }
+
+    /**
+     * Ask the current default engine to return a string of sample text to be
+     * spoken to the user.
+     */
+    private void getSampleText() {
+        String currentEngine = mTts.getCurrentEngine();
+
+        if (TextUtils.isEmpty(currentEngine)) currentEngine = mTts.getDefaultEngine();
+
+        maybeUpdateTtsLanguage(currentEngine);
+        Locale currentLocale = mTts.getLanguage();
+
+        // TODO: This is currently a hidden private API. The intent extras
+        // and the intent action should be made public if we intend to make this
+        // a public API. We fall back to using a canned set of strings if this
+        // doesn't work.
+        Intent intent = new Intent(TextToSpeech.Engine.ACTION_GET_SAMPLE_TEXT);
+
+        if (currentLocale != null) {
+            intent.putExtra("language", currentLocale.getLanguage());
+            intent.putExtra("country", currentLocale.getCountry());
+            intent.putExtra("variant", currentLocale.getVariant());
+        }
+        intent.setPackage(currentEngine);
+
+        try {
+            if (DBG) Log.d(TAG, "Getting sample text: " + intent.toUri(0));
+            startActivityForResult(intent, GET_SAMPLE_TEXT);
+        } catch (ActivityNotFoundException ex) {
+            Log.e(TAG, "Failed to get sample text, no activity found for " + intent + ")");
+        }
+    }
+
+    /**
+     * Called when the TTS engine is initialized.
+     */
+    public void onInitEngine(int status) {
+        if (status == TextToSpeech.SUCCESS) {
+            updateWidgetState(true);
+            if (DBG) Log.d(TAG, "TTS engine for settings screen initialized.");
+        } else {
+            if (DBG) Log.d(TAG, "TTS engine for settings screen failed to initialize successfully.");
+            updateWidgetState(false);
+        }
+    }
+
+    /**
+     * Called when voice data integrity check returns
+     */
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == GET_SAMPLE_TEXT) {
+            onSampleTextReceived(resultCode, data);
+        } else if (requestCode == VOICE_DATA_INTEGRITY_CHECK) {
+            onVoiceDataIntegrityCheckDone(data);
+        }
+    }
+
+    private String getDefaultSampleString() {
+        if (mTts != null && mTts.getLanguage() != null) {
+            final String currentLang = mTts.getLanguage().getISO3Language();
+            String[] strings = getActivity().getResources().getStringArray(
+                    R.array.tts_demo_strings);
+            String[] langs = getActivity().getResources().getStringArray(
+                    R.array.tts_demo_string_langs);
+
+            for (int i = 0; i < strings.length; ++i) {
+                if (langs[i].equals(currentLang)) {
+                    return strings[i];
+                }
+            }
+        }
+        return null;
+    }
+
+    private void onSampleTextReceived(int resultCode, Intent data) {
+        String sample = getDefaultSampleString();
+
+        if (resultCode == TextToSpeech.LANG_AVAILABLE && data != null) {
+            if (data != null && data.getStringExtra("sampleText") != null) {
+                sample = data.getStringExtra("sampleText");
+            }
+            if (DBG) Log.d(TAG, "Got sample text: " + sample);
+        } else {
+            if (DBG) Log.d(TAG, "Using default sample text :" + sample);
+        }
+
+        if (sample != null && mTts != null) {
+            // The engine is guaranteed to have been initialized here
+            // because this preference is not enabled otherwise.
+            mTts.speak(sample, TextToSpeech.QUEUE_FLUSH, null);
+        } else {
+            // TODO: Display an error here to the user.
+            Log.e(TAG, "Did not have a sample string for the requested language");
+        }
+    }
+
+    public boolean onPreferenceChange(Preference preference, Object objValue) {
+        if (KEY_DEFAULT_RATE.equals(preference.getKey())) {
+            // Default rate
+            mDefaultRate = Integer.parseInt((String) objValue);
+            try {
+                Settings.Secure.putInt(getContentResolver(), TTS_DEFAULT_RATE, mDefaultRate);
+                if (mTts != null) {
+                    mTts.setSpeechRate(mDefaultRate / 100.0f);
+                }
+                if (DBG) Log.d(TAG, "TTS default rate changed, now " + mDefaultRate);
+            } catch (NumberFormatException e) {
+                Log.e(TAG, "could not persist default TTS rate setting", e);
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Called when mPlayExample is clicked
+     */
+    public boolean onPreferenceClick(Preference preference) {
+        if (preference == mPlayExample) {
+            // Get the sample text from the TTS engine; onActivityResult will do
+            // the actual speaking
+            getSampleText();
+            return true;
+        }
+
+        return false;
+    }
+
+    private void updateWidgetState(boolean enable) {
+        mPlayExample.setEnabled(enable);
+        mDefaultRatePref.setEnabled(enable);
+    }
+
+    private void displayDataAlert(final String key) {
+        Log.i(TAG, "Displaying data alert for :" + key);
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        builder.setTitle(android.R.string.dialog_alert_title);
+        builder.setIcon(android.R.drawable.ic_dialog_alert);
+        builder.setMessage(getActivity().getString(
+                R.string.tts_engine_security_warning, mEnginesHelper.getEngineInfo(key).label));
+        builder.setCancelable(true);
+        builder.setPositiveButton(android.R.string.ok,
+                new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int which) {
+                       updateDefaultEngine(key);
+                    }
+                });
+        builder.setNegativeButton(android.R.string.cancel, null);
+
+        AlertDialog dialog = builder.create();
+        dialog.show();
+    }
+
+    private void updateDefaultEngine(String engine) {
+        if (DBG) Log.d(TAG, "Updating default synth to : " + engine);
+
+        // Disable the "play sample text" preference and the speech
+        // rate preference while the engine is being swapped.
+        updateWidgetState(false);
+
+        // Keep track of the previous engine that was being used. So that
+        // we can reuse the previous engine.
+        //
+        // Note that if TextToSpeech#getCurrentEngine is not null, it means at
+        // the very least that we successfully bound to the engine service.
+        mPreviousEngine = mTts.getCurrentEngine();
+
+        // Step 1: Shut down the existing TTS engine.
+        if (mTts != null) {
+            try {
+                mTts.shutdown();
+                mTts = null;
+            } catch (Exception e) {
+                Log.e(TAG, "Error shutting down TTS engine" + e);
+            }
+        }
+
+        // Step 2: Connect to the new TTS engine.
+        // Step 3 is continued on #onUpdateEngine (below) which is called when
+        // the app binds successfully to the engine.
+        if (DBG) Log.d(TAG, "Updating engine : Attempting to connect to engine: " + engine);
+        mTts = new TextToSpeech(getActivity().getApplicationContext(), mUpdateListener, engine);
+    }
+
+    /*
+     * Step 3: We have now bound to the TTS engine the user requested. We will
+     * attempt to check voice data for the engine if we successfully bound to it,
+     * or revert to the previous engine if we didn't.
+     */
+    public void onUpdateEngine(int status) {
+        if (status == TextToSpeech.SUCCESS) {
+            if (DBG) {
+                Log.d(TAG, "Updating engine: Successfully bound to the engine: " +
+                        mTts.getCurrentEngine());
+            }
+            checkVoiceData(mTts.getCurrentEngine());
+        } else {
+            if (DBG) Log.d(TAG, "Updating engine: Failed to bind to engine, reverting.");
+            if (mPreviousEngine != null) {
+                // This is guaranteed to at least bind, since mPreviousEngine would be
+                // null if the previous bind to this engine failed.
+                mTts = new TextToSpeech(getActivity().getApplicationContext(), mInitListener,
+                        mPreviousEngine);
+            }
+            mPreviousEngine = null;
+        }
+    }
+
+    /*
+     * Step 4: Check whether the voice data for the engine is ok.
+     */
+    private void checkVoiceData(String engine) {
+        Intent intent = new Intent(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
+        intent.setPackage(engine);
+        try {
+            if (DBG) Log.d(TAG, "Updating engine: Checking voice data: " + intent.toUri(0));
+            startActivityForResult(intent, VOICE_DATA_INTEGRITY_CHECK);
+        } catch (ActivityNotFoundException ex) {
+            Log.e(TAG, "Failed to check TTS data, no activity found for " + intent + ")");
+        }
+    }
+
+    /*
+     * Step 5: The voice data check is complete.
+     */
+    private void onVoiceDataIntegrityCheckDone(Intent data) {
+        final String engine = mTts.getCurrentEngine();
+
+        if (engine == null) {
+            Log.e(TAG, "Voice data check complete, but no engine bound");
+            return;
+        }
+
+        if (data == null){
+            Log.e(TAG, "Engine failed voice data integrity check (null return)" +
+                    mTts.getCurrentEngine());
+            return;
+        }
+
+        Settings.Secure.putString(getContentResolver(), TTS_DEFAULT_SYNTH, engine);
+
+        final int engineCount = mEnginePreferenceCategory.getPreferenceCount();
+        for (int i = 0; i < engineCount; ++i) {
+            final Preference p = mEnginePreferenceCategory.getPreference(i);
+            if (p instanceof TtsEnginePreference) {
+                TtsEnginePreference enginePref = (TtsEnginePreference) p;
+                if (enginePref.getKey().equals(engine)) {
+                    enginePref.setVoiceDataDetails(data);
+                    break;
+                }
+            }
+        }
+
+        updateWidgetState(true);
+    }
+
+    private boolean shouldDisplayDataAlert(String engine) {
+        final EngineInfo info = mEnginesHelper.getEngineInfo(engine);
+        return !info.system;
+    }
+
+    @Override
+    public Checkable getCurrentChecked() {
+        return mCurrentChecked;
+    }
+
+    @Override
+    public String getCurrentKey() {
+        return mCurrentEngine;
+    }
+
+    @Override
+    public void setCurrentChecked(Checkable current) {
+        mCurrentChecked = current;
+    }
+
+    @Override
+    public void setCurrentKey(String key) {
+        mCurrentEngine = key;
+        if (shouldDisplayDataAlert(mCurrentEngine)) {
+            displayDataAlert(mCurrentEngine);
+        } else {
+            updateDefaultEngine(mCurrentEngine);
+        }
+    }
+
+}
diff --git a/src/com/android/settings/tts/TtsEnginePreference.java b/src/com/android/settings/tts/TtsEnginePreference.java
new file mode 100644
index 0000000..b98a239
--- /dev/null
+++ b/src/com/android/settings/tts/TtsEnginePreference.java
@@ -0,0 +1,197 @@
+/*
+ * 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.tts;
+
+import com.android.settings.R;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.speech.tts.TextToSpeech.EngineInfo;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Checkable;
+import android.widget.CompoundButton;
+import android.widget.RadioButton;
+
+
+public class TtsEnginePreference extends Preference {
+
+    /**
+     * Key for the name of the TTS engine passed in to the engine
+     * settings fragment {@link TtsEngineSettingsFragment}.
+     */
+    static final String FRAGMENT_ARGS_NAME = "name";
+
+    /**
+     * Key for the label of the TTS engine passed in to the engine
+     * settings fragment. This is used as the title of the fragment
+     * {@link TtsEngineSettingsFragment}.
+     */
+    static final String FRAGMENT_ARGS_LABEL = "label";
+
+    /**
+     * Key for the voice data data passed in to the engine settings
+     * fragmetn {@link TtsEngineSettingsFragment}.
+     */
+    static final String FRAGMENT_ARGS_VOICES = "voices";
+
+    /**
+     * The preference activity that owns this preference. Required
+     * for instantiating the engine specific settings screen.
+     */
+    private final PreferenceActivity mPreferenceActivity;
+
+    /**
+     * The engine information for the engine this preference represents.
+     * Contains it's name, label etc. which are used for display.
+     */
+    private final EngineInfo mEngineInfo;
+
+    /**
+     * The shared radio button state, which button is checked etc.
+     */
+    private final RadioButtonGroupState mSharedState;
+
+    /**
+     * When true, the change callbacks on the radio button will not
+     * fire.
+     */
+    private volatile boolean mPreventRadioButtonCallbacks;
+
+    private View mSettingsIcon;
+    private RadioButton mRadioButton;
+    private Intent mVoiceCheckData;
+
+    private final CompoundButton.OnCheckedChangeListener mRadioChangeListener =
+        new CompoundButton.OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                onRadioButtonClicked(buttonView, isChecked);
+            }
+        };
+
+    public TtsEnginePreference(Context context, EngineInfo info, RadioButtonGroupState state,
+            PreferenceActivity prefActivity) {
+        super(context);
+        setLayoutResource(R.layout.preference_tts_engine);
+
+        mSharedState = state;
+        mPreferenceActivity = prefActivity;
+        mEngineInfo = info;
+        mPreventRadioButtonCallbacks = false;
+
+        setKey(mEngineInfo.name);
+        setTitle(mEngineInfo.label);
+    }
+
+    @Override
+    public View getView(View convertView, ViewGroup parent) {
+        if (mSharedState == null) {
+            throw new IllegalStateException("Call to getView() before a call to" +
+                    "setSharedState()");
+        }
+
+        View view = super.getView(convertView, parent);
+        final RadioButton rb = (RadioButton) view.findViewById(R.id.tts_engine_radiobutton);
+        rb.setOnCheckedChangeListener(mRadioChangeListener);
+
+        boolean isChecked = getKey().equals(mSharedState.getCurrentKey());
+        if (isChecked) {
+            mSharedState.setCurrentChecked(rb);
+        }
+
+        mPreventRadioButtonCallbacks = true;
+        rb.setChecked(isChecked);
+        mPreventRadioButtonCallbacks = false;
+
+        mRadioButton = rb;
+
+        View textLayout = view.findViewById(R.id.tts_engine_pref_text);
+        textLayout.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                onRadioButtonClicked(rb, !rb.isChecked());
+            }
+        });
+
+        mSettingsIcon = view.findViewById(R.id.tts_engine_settings);
+        // Will be enabled only the engine has passed the voice check, and
+        // is currently enabled.
+        mSettingsIcon.setEnabled(isChecked && mVoiceCheckData != null);
+        mSettingsIcon.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Bundle args = new Bundle();
+                args.putString(FRAGMENT_ARGS_NAME, mEngineInfo.name);
+                args.putString(FRAGMENT_ARGS_LABEL, mEngineInfo.label);
+                if (mVoiceCheckData != null) {
+                    args.putParcelable(FRAGMENT_ARGS_VOICES, mVoiceCheckData);
+                }
+
+                // Note that we use this instead of the (easier to use)
+                // PreferenceActivity.startPreferenceFragment because the
+                // title will not be updated correctly in the fragment
+                // breadcrumb since it isn't inflated from the XML layout.
+                mPreferenceActivity.startPreferencePanel(
+                        TtsEngineSettingsFragment.class.getName(),
+                        args, 0, mEngineInfo.label, null, 0);
+            }
+        });
+
+        return view;
+    }
+
+    public void setVoiceDataDetails(Intent data) {
+        mVoiceCheckData = data;
+        mSettingsIcon.setEnabled(mRadioButton.isChecked());
+    }
+
+    private void onRadioButtonClicked(CompoundButton buttonView, boolean isChecked) {
+        if (mPreventRadioButtonCallbacks) {
+            return;
+        }
+
+        if (isChecked) {
+            if (mSharedState.getCurrentChecked() != null) {
+                mSharedState.getCurrentChecked().setChecked(false);
+            }
+            mSharedState.setCurrentChecked(buttonView);
+            mSharedState.setCurrentKey(getKey());
+            callChangeListener(mSharedState.getCurrentKey());
+        }
+
+        mSettingsIcon.setEnabled(isChecked);
+    }
+
+
+    /**
+     * Holds all state that is common to this group of radio buttons, such
+     * as the currently selected key and the currently checked compound button.
+     * (which corresponds to this key).
+     */
+    public interface RadioButtonGroupState {
+        String getCurrentKey();
+        Checkable getCurrentChecked();
+
+        void setCurrentKey(String key);
+        void setCurrentChecked(Checkable current);
+    }
+
+}
diff --git a/src/com/android/settings/tts/TtsEngineSettingsFragment.java b/src/com/android/settings/tts/TtsEngineSettingsFragment.java
new file mode 100644
index 0000000..d78f80d
--- /dev/null
+++ b/src/com/android/settings/tts/TtsEngineSettingsFragment.java
@@ -0,0 +1,200 @@
+/*
+ * 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.tts;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.os.Bundle;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceScreen;
+import android.speech.tts.TextToSpeech;
+import android.speech.tts.TtsEngines;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+
+public class TtsEngineSettingsFragment extends SettingsPreferenceFragment implements
+        OnPreferenceClickListener, OnPreferenceChangeListener {
+    private static final String TAG = "TtsEngineSettings";
+    private static final boolean DBG = false;
+
+    private static final String KEY_ENGINE_LOCALE = "tts_default_lang";
+    private static final String KEY_ENGINE_SETTINGS = "tts_engine_settings";
+    private static final String KEY_INSTALL_DATA = "tts_install_data";
+
+    private TtsEngines mEnginesHelper;
+    private ListPreference mLocalePreference;
+    private Preference mEngineSettingsPreference;
+    private Preference mInstallVoicesPreference;
+    private Intent mEngineSettingsIntent;
+
+    public TtsEngineSettingsFragment() {
+        super();
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        addPreferencesFromResource(R.xml.tts_engine_settings);
+        mEnginesHelper = new TtsEngines(getActivity());
+
+        final PreferenceScreen root = getPreferenceScreen();
+        mLocalePreference = (ListPreference) root.findPreference(KEY_ENGINE_LOCALE);
+        mLocalePreference.setOnPreferenceChangeListener(this);
+        mEngineSettingsPreference = root.findPreference(KEY_ENGINE_SETTINGS);
+        mEngineSettingsPreference.setOnPreferenceClickListener(this);
+        mInstallVoicesPreference = root.findPreference(KEY_INSTALL_DATA);
+        mInstallVoicesPreference.setOnPreferenceClickListener(this);
+
+        root.setTitle(getEngineLabel());
+        root.setKey(getEngineName());
+        mEngineSettingsPreference.setTitle(getResources().getString(
+                R.string.tts_engine_settings_title, getEngineLabel()));
+
+        mEngineSettingsIntent = mEnginesHelper.getSettingsIntent(getEngineName());
+        if (mEngineSettingsIntent == null) {
+            mEngineSettingsPreference.setEnabled(false);
+        }
+        mInstallVoicesPreference.setEnabled(false);
+
+        updateVoiceDetails();
+    }
+
+    private void updateVoiceDetails() {
+        final Intent voiceDataDetails = getArguments().getParcelable(
+                TtsEnginePreference.FRAGMENT_ARGS_VOICES);
+        if (DBG) Log.d(TAG, "Parsing voice data details, data: " + voiceDataDetails.toUri(0));
+        ArrayList<String> available = voiceDataDetails.getStringArrayListExtra(
+                TextToSpeech.Engine.EXTRA_AVAILABLE_VOICES);
+        ArrayList<String> unavailable = voiceDataDetails.getStringArrayListExtra(
+                TextToSpeech.Engine.EXTRA_UNAVAILABLE_VOICES);
+
+        if (available == null || unavailable == null){
+            Log.e(TAG, "TTS data check failed (available == null).");
+            return;
+        }
+
+        if (unavailable.size() > 0) {
+            mInstallVoicesPreference.setEnabled(true);
+        }
+
+        if (available.size() > 0) {
+            updateDefaultLocalePref(available);
+        } else {
+            final CharSequence[] empty = new CharSequence[0];
+            mLocalePreference.setEntries(empty);
+            mLocalePreference.setEntryValues(empty);
+        }
+    }
+
+    private void updateDefaultLocalePref(ArrayList<String> availableLangs) {
+        String currentLocale = mEnginesHelper.getLocalePrefForEngine(
+                getEngineName());
+
+        CharSequence[] entries = new CharSequence[availableLangs.size()];
+        CharSequence[] entryValues = new CharSequence[availableLangs.size()];
+
+        int selectedLanguageIndex = -1;
+        for (int i = 0; i < availableLangs.size(); i++) {
+            String[] langCountryVariant = availableLangs.get(i).split("-");
+            Locale loc = null;
+            if (langCountryVariant.length == 1){
+                loc = new Locale(langCountryVariant[0]);
+            } else if (langCountryVariant.length == 2){
+                loc = new Locale(langCountryVariant[0], langCountryVariant[1]);
+            } else if (langCountryVariant.length == 3){
+                loc = new Locale(langCountryVariant[0], langCountryVariant[1],
+                                 langCountryVariant[2]);
+            }
+            if (loc != null){
+                entries[i] = loc.getDisplayName();
+                entryValues[i] = availableLangs.get(i);
+                if (entryValues[i].equals(currentLocale)) {
+                    selectedLanguageIndex = i;
+                }
+            }
+        }
+
+        mLocalePreference.setEntries(entries);
+        mLocalePreference.setEntryValues(entryValues);
+        if (selectedLanguageIndex > -1) {
+            mLocalePreference.setValueIndex(selectedLanguageIndex);
+        } else {
+            mLocalePreference.setValueIndex(0);
+            mEnginesHelper.updateLocalePrefForEngine(getEngineName(),
+                    availableLangs.get(0));
+        }
+    }
+
+    /**
+     * Ask the current default engine to launch the matching INSTALL_TTS_DATA activity
+     * so the required TTS files are properly installed.
+     */
+    private void installVoiceData() {
+        if (TextUtils.isEmpty(getEngineName())) return;
+        Intent intent = new Intent(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setPackage(getEngineName());
+        try {
+            Log.v(TAG, "Installing voice data: " + intent.toUri(0));
+            startActivity(intent);
+        } catch (ActivityNotFoundException ex) {
+            Log.e(TAG, "Failed to install TTS data, no acitivty found for " + intent + ")");
+        }
+    }
+
+    @Override
+    public boolean onPreferenceClick(Preference preference) {
+        if (preference == mInstallVoicesPreference) {
+            installVoiceData();
+            return true;
+        } else if (preference == mEngineSettingsPreference) {
+            startActivity(mEngineSettingsIntent);
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        if (preference == mLocalePreference) {
+            mEnginesHelper.updateLocalePrefForEngine(getEngineName(), (String) newValue);
+            return true;
+        }
+
+        return false;
+    }
+
+    private String getEngineName() {
+        return getArguments().getString(TtsEnginePreference.FRAGMENT_ARGS_NAME);
+    }
+
+    private String getEngineLabel() {
+        return getArguments().getString(TtsEnginePreference.FRAGMENT_ARGS_LABEL);
+    }
+
+}
diff --git a/src/com/android/settings/wifi/AccessPoint.java b/src/com/android/settings/wifi/AccessPoint.java
index 799a8da..03e7ba4 100644
--- a/src/com/android/settings/wifi/AccessPoint.java
+++ b/src/com/android/settings/wifi/AccessPoint.java
@@ -358,4 +358,19 @@
             setSummary(summary.toString());
         }
     }
+
+    /**
+     * Generate and save a default wifiConfiguration with common values.
+     * Can only be called for unsecured networks.
+     * @hide
+     */
+    protected void generateOpenNetworkConfig() {
+        if (security != SECURITY_NONE)
+            throw new IllegalStateException();
+        if (mConfig != null)
+            return;
+        mConfig = new WifiConfiguration();
+        mConfig.SSID = AccessPoint.convertToQuotedString(ssid);
+        mConfig.allowedKeyManagement.set(KeyMgmt.NONE);
+    }
 }
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index e38f5d9..188765f 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -353,11 +353,9 @@
                         mWifiManager.connectNetwork(mSelectedAccessPoint.networkId);
                     }
                 } else if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE) {
-                    // Shortcut for open networks.
-                    WifiConfiguration config = new WifiConfiguration();
-                    config.SSID = AccessPoint.convertToQuotedString(mSelectedAccessPoint.ssid);
-                    config.allowedKeyManagement.set(KeyMgmt.NONE);
-                    mWifiManager.connectNetwork(config);
+                    /** Bypass dialog for unsecured networks */
+                    mSelectedAccessPoint.generateOpenNetworkConfig();
+                    mWifiManager.connectNetwork(mSelectedAccessPoint.getConfig());
                 } else {
                     showConfigUi(mSelectedAccessPoint, true);
                 }
@@ -379,7 +377,14 @@
     public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
         if (preference instanceof AccessPoint) {
             mSelectedAccessPoint = (AccessPoint) preference;
-            showConfigUi(mSelectedAccessPoint, false);
+            /** Bypass dialog for unsecured, unsaved networks */
+            if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE &&
+                    mSelectedAccessPoint.networkId == INVALID_NETWORK_ID) {
+                mSelectedAccessPoint.generateOpenNetworkConfig();
+                mWifiManager.connectNetwork(mSelectedAccessPoint.getConfig());
+            } else {
+                showConfigUi(mSelectedAccessPoint, false);
+            }
         } else {
             return super.onPreferenceTreeClick(screen, preference);
         }
@@ -623,6 +628,7 @@
         }
 
         void forceScan() {
+            removeMessages(0);
             sendEmptyMessage(0);
         }