Merge "Move theme setting out of tuner to display"
diff --git a/res/layout/preference_tts_engine.xml b/res/layout/preference_tts_engine.xml
index 8f4036b..19401f0 100644
--- a/res/layout/preference_tts_engine.xml
+++ b/res/layout/preference_tts_engine.xml
@@ -31,17 +31,4 @@
android:maxLines="2"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee"/>
-
- <ImageView
- android:id="@+id/tts_engine_settings"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:src="@drawable/ic_settings"
- android:contentDescription="@string/tts_engine_settings_button"
- android:layout_centerVertical="true"
- android:clickable="true"
- android:focusable="true"
- android:background="?android:attr/selectableItemBackground"/>
</LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 818ff9f..4b93d8c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4624,9 +4624,20 @@
behalf. It comes from the <xliff:g id="voice_input_service_app_name">%s</xliff:g>
application. Enable the use of this service?</string>
- <!-- On main TTS Settings screen, in default settings section, reset speech rate for synthesized voice to 1x speech rate.-->
+ <!-- [CHAR LIMIT=50] The text for the settings section that is used to set a preferred text to speech engine -->
+ <string name="tts_engine_preference_title">Preferred engine</string>
+ <!-- [CHAR LIMIT=50] The text for a settings screen of the currently set text to speech engine -->
+ <string name="tts_engine_settings_title">Engine settings</string>
+ <!-- [CHAR LIMIT=50] The text for a button that goes to the speech rate and pitch settings for text to speech. -->
+ <string name="tts_sliders_title">Speech rate & pitch</string>
+ <!-- [CHAR LIMIT=50] Name for the general text to speech settings section. -->
+ <string name="tts_engine_section_title">Engine</string>
+ <!-- [CHAR LIMIT=50] Name for the button that goes to the voice selection screen. -->
+ <string name="tts_install_voice_title">Voices</string>
+
+ <!-- Reset speech rate for synthesized voice to 1x speech rate in the text to speech settings.-->
<string name="tts_reset_speech_rate_title">Reset speech rate</string>
- <!-- On main TTS Settings screen, summary for reset speech rate for synthesized voice -->
+ <!-- Summary for reset speech rate for synthesized voice in the text to speech settings.-->
<string name="tts_reset_speech_rate_summary">Reset the speed at which the text is spoken to normal.</string>
<!-- Power Control Widget -->
diff --git a/res/xml/tts_engine_picker.xml b/res/xml/tts_engine_picker.xml
new file mode 100644
index 0000000..61e3e7e
--- /dev/null
+++ b/res/xml/tts_engine_picker.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ android:title="@string/tts_settings_title">
+
+ <PreferenceCategory android:key="tts_engine_preference_category"
+ android:title="@string/tts_engine_preference_title"/>
+
+</PreferenceScreen>
diff --git a/res/xml/tts_engine_settings.xml b/res/xml/tts_engine_settings.xml
deleted file mode 100644
index d00c102..0000000
--- a/res/xml/tts_engine_settings.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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:order="100" />
-
- <Preference
- android:key="tts_engine_settings"
- android:persistent="false"
- android:title="@string/tts_engine_settings_title"
- android:order="200" />
-
- <Preference
- android:key="tts_install_data"
- android:persistent="false"
- android:title="@string/tts_install_data_title"
- android:summary="@string/tts_install_data_summary"
- android:order="300" />
-</PreferenceScreen>
diff --git a/res/xml/tts_settings.xml b/res/xml/tts_settings.xml
index 31d2b17..b02a749 100644
--- a/res/xml/tts_settings.xml
+++ b/res/xml/tts_settings.xml
@@ -17,38 +17,40 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/tts_settings_title">
- <!-- 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_engine_section"
+ android:title="@string/tts_engine_section_title">
+
+ <com.android.settingslib.RestrictedPreference android:key="tts_engine_preference"
+ android:title="@string/tts_engine_preference_title"
+ android:fragment="com.android.settings.tts.TtsEnginePreferenceFragment"/>
+
+ <Preference
+ android:key="tts_engine_settings"
+ android:persistent="false"
+ android:title="@string/tts_engine_settings_title"
+ android:order="200" />
+
+ <Preference
+ android:key="tts_install_data"
+ android:persistent="false"
+ android:title="@string/tts_install_voice_title"
+ android:order="300" />
+
+ </PreferenceCategory>
<PreferenceCategory android:key="tts_general_section"
android:title="@string/tts_general_section_title">
- <!-- The max value for seek bars here should be kept in sync
- with the max value specified in TextToSpeechSettings class. -->
- <com.android.settings.SeekBarPreference
- android:key="tts_default_rate"
- android:title="@string/tts_default_rate_title"
- android:summary="@string/tts_default_rate_summary"
- android:defaultValue="50"
- android:max="600"/>
- <com.android.settings.SeekBarPreference
- android:key="tts_default_pitch"
- android:title="@string/tts_default_pitch_title"
- android:summary="@string/tts_default_pitch_summary"
- android:defaultValue="100"
- android:max="400"/>
+ <com.android.settingslib.RestrictedPreference
+ android:key="tts_sliders"
+ android:title="@string/tts_sliders_title"
+ android:fragment="com.android.settings.tts.TtsSlidersFragment"/>
- <Preference android:key="reset_speech_rate"
- android:persistent="false"
- android:title="@string/tts_reset_speech_rate_title"
- android:summary="@string/tts_reset_speech_rate_summary" />
-
- <Preference android:key="reset_speech_pitch"
- android:persistent="false"
- android:title="@string/tts_reset_speech_pitch_title"
- android:summary="@string/tts_reset_speech_pitch_summary" />
+ <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_play_example"
android:persistent="false"
diff --git a/res/xml/tts_sliders.xml b/res/xml/tts_sliders.xml
new file mode 100644
index 0000000..3c767b0
--- /dev/null
+++ b/res/xml/tts_sliders.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ android:title="@string/tts_settings_title">
+
+ <!-- The max value for seek bars here should be kept in sync
+ with the max value specified in TextToSpeechSettings class. -->
+ <com.android.settings.SeekBarPreference
+ android:key="tts_default_rate"
+ android:title="@string/tts_default_rate_title"
+ android:summary="@string/tts_default_rate_summary"
+ android:defaultValue="50"
+ android:max="600"/>
+
+ <com.android.settings.SeekBarPreference
+ android:key="tts_default_pitch"
+ android:title="@string/tts_default_pitch_title"
+ android:summary="@string/tts_default_pitch_summary"
+ android:defaultValue="100"
+ android:max="400"/>
+
+ <Preference android:key="reset_speech_rate"
+ android:persistent="false"
+ android:title="@string/tts_reset_speech_rate_title"
+ android:summary="@string/tts_reset_speech_rate_summary" />
+
+ <Preference android:key="reset_speech_pitch"
+ android:persistent="false"
+ android:title="@string/tts_reset_speech_pitch_title"
+ android:summary="@string/tts_reset_speech_pitch_summary" />
+
+</PreferenceScreen>
diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
index b956aa5..3fc0abf 100644
--- a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
+++ b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
@@ -284,12 +284,12 @@
}
}
if (btClass != null) {
- if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) {
- return new Pair<Integer, String>(R.drawable.ic_bt_headphones_a2dp, HEADPHONE);
- }
- if (btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
+ if (btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
return new Pair<Integer, String>(R.drawable.ic_bt_headset_hfp, HEADSET);
}
+ if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) {
+ return new Pair<Integer, String>(R.drawable.ic_bt_headphones_a2dp, HEADPHONE);
+ }
}
return new Pair<Integer, String>(R.drawable.ic_settings_bluetooth, BLUETOOTH);
}
diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java
index 4f9f92c..5040e45 100644
--- a/src/com/android/settings/search/SearchIndexableResources.java
+++ b/src/com/android/settings/search/SearchIndexableResources.java
@@ -72,6 +72,8 @@
import com.android.settings.print.PrintSettingsFragment;
import com.android.settings.sim.SimSettings;
import com.android.settings.system.SystemDashboardFragment;
+import com.android.settings.tts.TtsEnginePreferenceFragment;
+import com.android.settings.tts.TtsSlidersFragment;
import com.android.settings.users.UserSettings;
import com.android.settings.wifi.AdvancedWifiSettings;
import com.android.settings.wifi.ConfigureWifiSettings;
@@ -167,6 +169,9 @@
addIndex(ConnectedDeviceDashboardFragment.class, NO_DATA_RES_ID, R.drawable.ic_bt_laptop);
addIndex(EnterprisePrivacySettings.class, NO_DATA_RES_ID, R.drawable.ic_settings_about);
addIndex(PaymentSettings.class, NO_DATA_RES_ID, R.drawable.ic_settings_nfc_payment);
+ addIndex(
+ TtsEnginePreferenceFragment.class, NO_DATA_RES_ID, R.drawable.ic_settings_language);
+ addIndex(TtsSlidersFragment.class, NO_DATA_RES_ID, R.drawable.ic_settings_language);
}
private SearchIndexableResources() {
diff --git a/src/com/android/settings/tts/TextToSpeechSettings.java b/src/com/android/settings/tts/TextToSpeechSettings.java
index 96a7f4e..fe78d20 100644
--- a/src/com/android/settings/tts/TextToSpeechSettings.java
+++ b/src/com/android/settings/tts/TextToSpeechSettings.java
@@ -16,29 +16,27 @@
package com.android.settings.tts;
+import android.support.v7.preference.ListPreference;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Intent;
import android.os.Bundle;
-import android.provider.Settings.SettingNotFoundException;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.EngineInfo;
import android.speech.tts.TtsEngines;
import android.speech.tts.UtteranceProgressListener;
-import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceCategory;
import android.text.TextUtils;
import android.util.Log;
-import android.widget.Checkable;
+import android.util.Pair;
+import java.util.Comparator;
+import java.util.Collections;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
-import com.android.settings.SeekBarPreference;
import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.tts.TtsEnginePreference.RadioButtonGroupState;
import java.util.ArrayList;
import java.util.HashMap;
@@ -48,13 +46,15 @@
import java.util.Objects;
import java.util.Set;
-import static android.provider.Settings.Secure.TTS_DEFAULT_PITCH;
-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_PITCH;
-public class TextToSpeechSettings extends SettingsPreferenceFragment implements
- Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener,
- RadioButtonGroupState {
+public class TextToSpeechSettings extends SettingsPreferenceFragment
+ implements Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener {
+
+ private static final String STATE_KEY_LOCALE_ENTRIES = "locale_entries";
+ private static final String STATE_KEY_LOCALE_ENTRY_VALUES = "locale_entry_values";
+ private static final String STATE_KEY_LOCALE_VALUE = "locale_value";
private static final String TAG = "TextToSpeechSettings";
private static final boolean DBG = false;
@@ -62,84 +62,37 @@
/** Preference key for the "play TTS example" preference. */
private static final String KEY_PLAY_EXAMPLE = "tts_play_example";;
- /** Preference key for the TTS pitch selection slider. */
- private static final String KEY_DEFAULT_PITCH = "tts_default_pitch";
-
- /** Preference key for the TTS rate selection slider. */
- private static final String KEY_DEFAULT_RATE = "tts_default_rate";
-
- /** Preference key for the TTS reset speech rate preference. */
- private static final String KEY_RESET_SPEECH_RATE = "reset_speech_rate";
-
- /** Preference key for the TTS reset speech pitch preference. */
- private static final String KEY_RESET_SPEECH_PITCH = "reset_speech_pitch";
-
/** Preference key for the TTS status field. */
private static final String KEY_STATUS = "tts_status";
/**
- * 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;
- /**
- * Speech rate value.
- * This value should be kept in sync with the max value set in tts_settings xml.
- */
- private static final int MAX_SPEECH_RATE = 600;
- private static final int MIN_SPEECH_RATE = 10;
-
- /**
- * Speech pitch value.
- * TTS pitch value varies from 25 to 400, where 100 is the value
- * for normal pitch. The max pitch value is set to 400, based on feedback from users
- * and the GoogleTTS pitch variation range. The range for pitch is not set in stone
- * and should be readjusted based on user need.
- * This value should be kept in sync with the max value set in tts_settings xml.
- */
- private static final int MAX_SPEECH_PITCH = 400;
- private static final int MIN_SPEECH_PITCH = 25;
-
- private PreferenceCategory mEnginePreferenceCategory;
- private SeekBarPreference mDefaultPitchPref;
- private SeekBarPreference mDefaultRatePref;
- private Preference mResetSpeechRate;
- private Preference mResetSpeechPitch;
private Preference mPlayExample;
private Preference mEngineStatus;
- private int mDefaultPitch = TextToSpeech.Engine.DEFAULT_PITCH;
- private int mDefaultRate = TextToSpeech.Engine.DEFAULT_RATE;
- /**
- * The currently selected engine.
- */
+ 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 int mSelectedLocaleIndex = -1;
+
+ /** 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;
private String mSampleText = null;
+ private ListPreference mLocalePreference;
+ private Preference mEngineSettingsPreference;
+ private Preference mInstallVoicesPreference;
+
/**
* Default locale used by selected TTS engine, null if not connected to any engine.
*/
@@ -164,18 +117,6 @@
}
};
- /**
- * 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 int getMetricsCategory() {
return MetricsEvent.TTS_TEXT_TO_SPEECH;
@@ -192,21 +133,40 @@
mPlayExample.setOnPreferenceClickListener(this);
mPlayExample.setEnabled(false);
- mResetSpeechRate = findPreference(KEY_RESET_SPEECH_RATE);
- mResetSpeechRate.setOnPreferenceClickListener(this);
- mResetSpeechPitch = findPreference(KEY_RESET_SPEECH_PITCH);
- mResetSpeechPitch.setOnPreferenceClickListener(this);
+ mEnginesHelper = new TtsEngines(getActivity().getApplicationContext());
- mEnginePreferenceCategory = (PreferenceCategory) findPreference(
- KEY_ENGINE_PREFERENCE_SECTION);
- mDefaultPitchPref = (SeekBarPreference) findPreference(KEY_DEFAULT_PITCH);
- mDefaultRatePref = (SeekBarPreference) findPreference(KEY_DEFAULT_RATE);
+ mLocalePreference = (ListPreference) findPreference(KEY_ENGINE_LOCALE);
+ mLocalePreference.setOnPreferenceChangeListener(this);
+
+ if (savedInstanceState == null) {
+ mLocalePreference.setEnabled(false);
+ mLocalePreference.setEntries(new CharSequence[0]);
+ mLocalePreference.setEntryValues(new CharSequence[0]);
+ } else {
+ // Repopulate mLocalePreference with saved state. Will be updated later with
+ // up-to-date values when checkTtsData() calls back with results.
+ final CharSequence[] entries =
+ savedInstanceState.getCharSequenceArray(STATE_KEY_LOCALE_ENTRIES);
+ final CharSequence[] entryValues =
+ savedInstanceState.getCharSequenceArray(STATE_KEY_LOCALE_ENTRY_VALUES);
+ final CharSequence value = savedInstanceState.getCharSequence(STATE_KEY_LOCALE_VALUE);
+
+ mLocalePreference.setEntries(entries);
+ mLocalePreference.setEntryValues(entryValues);
+ mLocalePreference.setValue(value != null ? value.toString() : null);
+ mLocalePreference.setEnabled(entries.length > 0);
+ }
+
+ mEngineSettingsPreference = findPreference(KEY_ENGINE_SETTINGS);
+ mEngineSettingsPreference.setOnPreferenceClickListener(this);
+ mInstallVoicesPreference = findPreference(KEY_INSTALL_DATA);
+ mInstallVoicesPreference.setOnPreferenceClickListener(this);
+ mInstallVoicesPreference.setEnabled(false);
mEngineStatus = findPreference(KEY_STATUS);
updateEngineStatus(R.string.tts_status_checking);
mTts = new TextToSpeech(getActivity().getApplicationContext(), mInitListener);
- mEnginesHelper = new TtsEngines(getActivity().getApplicationContext());
setTtsUtteranceProgressListener();
initSettings();
@@ -222,6 +182,23 @@
if (mTts == null || mCurrentDefaultLocale == null) {
return;
}
+ if (!mTts.getDefaultEngine().equals(mTts.getCurrentEngine())) {
+ try {
+ mTts.shutdown();
+ mTts = null;
+ } catch (Exception e) {
+ Log.e(TAG, "Error shutting down TTS engine" + e);
+ }
+ mTts = new TextToSpeech(getActivity().getApplicationContext(), mInitListener);
+ setTtsUtteranceProgressListener();
+ initSettings();
+ } else {
+ // Do set pitch correctly after it may have changed, and unlike speed, it doesn't change
+ // immediately.
+ final ContentResolver resolver = getContentResolver();
+ mTts.setPitch(android.provider.Settings.Secure.getInt(resolver, TTS_DEFAULT_PITCH, TextToSpeech.Engine.DEFAULT_PITCH)/100.0f);
+ }
+
Locale ttsDefaultLocale = mTts.getDefaultLanguage();
if (mCurrentDefaultLocale != null && !mCurrentDefaultLocale.equals(ttsDefaultLocale)) {
updateWidgetState(false);
@@ -259,26 +236,9 @@
private void initSettings() {
final ContentResolver resolver = getContentResolver();
- // Set up the default rate and pitch.
- mDefaultRate = android.provider.Settings.Secure.getInt(
- resolver, TTS_DEFAULT_RATE, TextToSpeech.Engine.DEFAULT_RATE);
- mDefaultPitch = android.provider.Settings.Secure.getInt(
- resolver, TTS_DEFAULT_PITCH, TextToSpeech.Engine.DEFAULT_PITCH);
-
- mDefaultRatePref.setProgress(getSeekBarProgressFromValue(KEY_DEFAULT_RATE, mDefaultRate));
- mDefaultRatePref.setOnPreferenceChangeListener(this);
- mDefaultRatePref.setMax(getSeekBarProgressFromValue(KEY_DEFAULT_RATE, MAX_SPEECH_RATE));
-
- mDefaultPitchPref.setProgress(getSeekBarProgressFromValue(KEY_DEFAULT_PITCH,
- mDefaultPitch));
- mDefaultPitchPref.setOnPreferenceChangeListener(this);
- mDefaultPitchPref.setMax(getSeekBarProgressFromValue(KEY_DEFAULT_PITCH,
- MAX_SPEECH_PITCH));
-
if (mTts != null) {
mCurrentEngine = mTts.getCurrentEngine();
- mTts.setSpeechRate(mDefaultRate/100.0f);
- mTts.setPitch(mDefaultPitch/100.0f);
+ mTts.setPitch(android.provider.Settings.Secure.getInt(resolver, TTS_DEFAULT_PITCH, TextToSpeech.Engine.DEFAULT_PITCH)/100.0f);
}
SettingsActivity activity = null;
@@ -289,53 +249,37 @@
"Settings");
}
- mEnginePreferenceCategory.removeAll();
+ if (mCurrentEngine != null) {
+ EngineInfo info = mEnginesHelper.getEngineInfo(mCurrentEngine);
+ mEngineSettingsPreference.setSummary(info.label);
+ final Intent settingsIntent = mEnginesHelper.getSettingsIntent(info.name);
+ mEngineSettingsPreference.setIntent(settingsIntent);
+ if (settingsIntent == null) {
+ mEngineSettingsPreference.setEnabled(false);
+ }
- List<EngineInfo> engines = mEnginesHelper.getEngines();
- for (EngineInfo engine : engines) {
- TtsEnginePreference enginePref = new TtsEnginePreference(getPrefContext(), engine,
- this, activity);
- mEnginePreferenceCategory.addPreference(enginePref);
+ Preference mEnginePreference = findPreference("tts_engine_preference");
+ mEnginePreference.setSummary(info.label);
}
checkVoiceData(mCurrentEngine);
}
/**
- * The minimum speech pitch/rate value should be > 0 but the minimum value of a seekbar in
- * android is fixed at 0. Therefore, we increment the seekbar progress with MIN_SPEECH_VALUE
- * so that the minimum seekbar progress value is MIN_SPEECH_PITCH/RATE.
- * SPEECH_VALUE = MIN_SPEECH_VALUE + SEEKBAR_PROGRESS
- */
- private int getValueFromSeekBarProgress(String preferenceKey, int progress) {
- if (preferenceKey.equals(KEY_DEFAULT_RATE)) {
- return MIN_SPEECH_RATE + progress;
- } else if (preferenceKey.equals(KEY_DEFAULT_PITCH)) {
- return MIN_SPEECH_PITCH + progress;
- }
- return progress;
- }
-
- /**
- * Since we are appending the MIN_SPEECH value to the speech seekbar progress, the
- * speech seekbar progress should be set to (speechValue - MIN_SPEECH value).
- */
- private int getSeekBarProgressFromValue(String preferenceKey, int value) {
- if (preferenceKey.equals(KEY_DEFAULT_RATE)) {
- return value - MIN_SPEECH_RATE;
- } else if (preferenceKey.equals(KEY_DEFAULT_PITCH)) {
- return value - MIN_SPEECH_PITCH;
- }
- return value;
- }
-
- /**
* Called when the TTS engine is initialized.
*/
public void onInitEngine(int status) {
if (status == TextToSpeech.SUCCESS) {
if (DBG) Log.d(TAG, "TTS engine for settings screen initialized.");
checkDefaultLocale();
+ getActivity()
+ .runOnUiThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ mLocalePreference.setEnabled(true);
+ }
+ });
} else {
if (DBG) Log.d(TAG, "TTS engine for settings screen failed to initialize successfully.");
updateWidgetState(false);
@@ -452,9 +396,88 @@
onSampleTextReceived(resultCode, data);
} else if (requestCode == VOICE_DATA_INTEGRITY_CHECK) {
onVoiceDataIntegrityCheckDone(data);
+ if (resultCode != TextToSpeech.Engine.CHECK_VOICE_DATA_FAIL) {
+ updateDefaultLocalePref(data);
+ }
}
}
+ private void updateDefaultLocalePref(Intent data) {
+ final ArrayList<String> availableLangs =
+ data.getStringArrayListExtra(TextToSpeech.Engine.EXTRA_AVAILABLE_VOICES);
+
+ final ArrayList<String> unavailableLangs =
+ data.getStringArrayListExtra(TextToSpeech.Engine.EXTRA_UNAVAILABLE_VOICES);
+
+ if (availableLangs != null && unavailableLangs.size() > 0) {
+ mInstallVoicesPreference.setEnabled(true);
+ } else {
+ mInstallVoicesPreference.setEnabled(false);
+ }
+
+ if (availableLangs == null || availableLangs.size() == 0) {
+ mLocalePreference.setEnabled(false);
+ return;
+ }
+ Locale currentLocale = null;
+ if (!mEnginesHelper.isLocaleSetToDefaultForEngine(mTts.getCurrentEngine())) {
+ currentLocale = mEnginesHelper.getLocalePrefForEngine(mTts.getCurrentEngine());
+ }
+
+ ArrayList<Pair<String, Locale>> entryPairs =
+ new ArrayList<Pair<String, Locale>>(availableLangs.size());
+ for (int i = 0; i < availableLangs.size(); i++) {
+ Locale locale = mEnginesHelper.parseLocaleString(availableLangs.get(i));
+ if (locale != null) {
+ entryPairs.add(new Pair<String, Locale>(locale.getDisplayName(), locale));
+ }
+ }
+
+ // Sort it
+ Collections.sort(
+ entryPairs,
+ new Comparator<Pair<String, Locale>>() {
+ @Override
+ public int compare(Pair<String, Locale> lhs, Pair<String, Locale> rhs) {
+ return lhs.first.compareToIgnoreCase(rhs.first);
+ }
+ });
+
+ // Get two arrays out of one of pairs
+ mSelectedLocaleIndex = 0; // Will point to the R.string.tts_lang_use_system value
+ CharSequence[] entries = new CharSequence[availableLangs.size() + 1];
+ CharSequence[] entryValues = new CharSequence[availableLangs.size() + 1];
+
+ entries[0] = getActivity().getString(R.string.tts_lang_use_system);
+ entryValues[0] = "";
+
+ int i = 1;
+ for (Pair<String, Locale> entry : entryPairs) {
+ if (entry.second.equals(currentLocale)) {
+ mSelectedLocaleIndex = i;
+ }
+ entries[i] = entry.first;
+ entryValues[i++] = entry.second.toString();
+ }
+
+ mLocalePreference.setEntries(entries);
+ mLocalePreference.setEntryValues(entryValues);
+ mLocalePreference.setEnabled(true);
+ setLocalePreference(mSelectedLocaleIndex);
+ }
+
+ /** Set entry from entry table in mLocalePreference */
+ private void setLocalePreference(int index) {
+ if (index < 0) {
+ mLocalePreference.setValue("");
+ mLocalePreference.setSummary(R.string.tts_lang_not_selected);
+ } else {
+ mLocalePreference.setValueIndex(index);
+ mLocalePreference.setSummary(mLocalePreference.getEntries()[index]);
+ }
+ }
+
+
private String getDefaultSampleString() {
if (mTts != null && mTts.getLanguage() != null) {
try {
@@ -522,17 +545,59 @@
@Override
public boolean onPreferenceChange(Preference preference, Object objValue) {
- if (KEY_DEFAULT_RATE.equals(preference.getKey())) {
- updateSpeechRate((Integer) objValue);
- } else if (KEY_DEFAULT_PITCH.equals(preference.getKey())) {
- updateSpeechPitchValue((Integer) objValue);
+ if (preference == mLocalePreference) {
+ String localeString = (String) objValue;
+ updateLanguageTo(
+ (!TextUtils.isEmpty(localeString)
+ ? mEnginesHelper.parseLocaleString(localeString)
+ : null));
+ checkDefaultLocale();
+ return true;
}
return true;
}
+ private void updateLanguageTo(Locale locale) {
+ int selectedLocaleIndex = -1;
+ String localeString = (locale != null) ? locale.toString() : "";
+ for (int i = 0; i < mLocalePreference.getEntryValues().length; i++) {
+ if (localeString.equalsIgnoreCase(mLocalePreference.getEntryValues()[i].toString())) {
+ selectedLocaleIndex = i;
+ break;
+ }
+ }
+
+ if (selectedLocaleIndex == -1) {
+ Log.w(TAG, "updateLanguageTo called with unknown locale argument");
+ return;
+ }
+ mLocalePreference.setSummary(mLocalePreference.getEntries()[selectedLocaleIndex]);
+ mSelectedLocaleIndex = selectedLocaleIndex;
+
+ mEnginesHelper.updateLocalePrefForEngine(mTts.getCurrentEngine(), locale);
+
+ // Null locale means "use system default"
+ mTts.setLanguage((locale != null) ? locale : Locale.getDefault());
+ }
+
/**
- * Called when mPlayExample, mResetSpeechRate or mResetSpeechPitch is
- * clicked.
+ * 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(mCurrentEngine)) return;
+ Intent intent = new Intent(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
+ intent.setPackage(mCurrentEngine);
+ 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 + ")");
+ }
+ }
+
+ /**
+ * Called when mPlayExample, mInstallVoicesPreference is clicked.
*/
@Override
public boolean onPreferenceClick(Preference preference) {
@@ -541,57 +606,15 @@
// the actual speaking
speakSampleText();
return true;
- } else if (preference == mResetSpeechRate) {
- int speechRateSeekbarProgress = getSeekBarProgressFromValue(
- KEY_DEFAULT_RATE, TextToSpeech.Engine.DEFAULT_RATE);
- mDefaultRatePref.setProgress(speechRateSeekbarProgress);
- updateSpeechRate(speechRateSeekbarProgress);
- return true;
- } else if (preference == mResetSpeechPitch) {
- int pitchSeekbarProgress = getSeekBarProgressFromValue(
- KEY_DEFAULT_PITCH, TextToSpeech.Engine.DEFAULT_PITCH);
- mDefaultPitchPref.setProgress(pitchSeekbarProgress);
- updateSpeechPitchValue(pitchSeekbarProgress);
- return true;
+ } else if (preference == mInstallVoicesPreference) {
+ installVoiceData();
+ return true;
}
return false;
}
- private void updateSpeechRate(int speechRateSeekBarProgress) {
- mDefaultRate = getValueFromSeekBarProgress(KEY_DEFAULT_RATE,
- speechRateSeekBarProgress);
- try {
- android.provider.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;
- }
-
- private void updateSpeechPitchValue(int speechPitchSeekBarProgress) {
- mDefaultPitch = getValueFromSeekBarProgress(KEY_DEFAULT_PITCH,
- speechPitchSeekBarProgress);
- try {
- android.provider.Settings.Secure.putInt(getContentResolver(),
- TTS_DEFAULT_PITCH, mDefaultPitch);
- if (mTts != null) {
- mTts.setPitch(mDefaultPitch / 100.0f);
- }
- if (DBG) Log.d(TAG, "TTS default pitch changed, now" + mDefaultPitch);
- } catch (NumberFormatException e) {
- Log.e(TAG, "could not persist default TTS pitch setting", e);
- }
- return;
- }
-
private void updateWidgetState(boolean enable) {
mPlayExample.setEnabled(enable);
- mDefaultRatePref.setEnabled(enable);
mEngineStatus.setEnabled(enable);
}
@@ -614,67 +637,7 @@
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);
- updateEngineStatus(R.string.tts_status_checking);
-
- // 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);
- setTtsUtteranceProgressListener();
- }
-
- /*
- * 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);
- setTtsUtteranceProgressListener();
- }
- mPreviousEngine = null;
- }
- }
-
- /*
- * Step 4: Check whether the voice data for the engine is ok.
- */
+ /** 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);
@@ -686,9 +649,7 @@
}
}
- /*
- * Step 5: The voice data check is complete.
- */
+ /** The voice data check is complete. */
private void onVoiceDataIntegrityCheckDone(Intent data) {
final String engine = mTts.getCurrentEngine();
@@ -715,39 +676,5 @@
if (evaluateDefaultLocale()) {
getSampleText();
}
-
- 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;
- }
- }
- }
}
-
- @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;
- updateDefaultEngine(mCurrentEngine);
- }
-
}
diff --git a/src/com/android/settings/tts/TtsEnginePreference.java b/src/com/android/settings/tts/TtsEnginePreference.java
index 385b861..9a84002 100644
--- a/src/com/android/settings/tts/TtsEnginePreference.java
+++ b/src/com/android/settings/tts/TtsEnginePreference.java
@@ -20,19 +20,16 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.os.Bundle;
import android.speech.tts.TextToSpeech.EngineInfo;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
import android.util.Log;
-import android.view.View;
import android.widget.Checkable;
import android.widget.CompoundButton;
import android.widget.RadioButton;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
-import com.android.settings.Utils;
public class TtsEnginePreference extends Preference {
@@ -40,31 +37,6 @@
private static final String TAG = "TtsEnginePreference";
/**
- * 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 SettingsActivity mSettingsActivity;
-
- /**
* The engine information for the engine this preference represents.
* Contains it's name, label etc. which are used for display.
*/
@@ -81,7 +53,6 @@
*/
private volatile boolean mPreventRadioButtonCallbacks;
- private View mSettingsIcon;
private RadioButton mRadioButton;
private Intent mVoiceCheckData;
@@ -99,7 +70,6 @@
setLayoutResource(R.layout.preference_tts_engine);
mSharedState = state;
- mSettingsActivity = prefActivity;
mEngineInfo = info;
mPreventRadioButtonCallbacks = false;
@@ -130,52 +100,10 @@
mPreventRadioButtonCallbacks = false;
mRadioButton = rb;
-
- 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);
- if (!isChecked) {
- mSettingsIcon.setAlpha(Utils.DISABLED_ALPHA);
- }
- 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)
- // SettingsActivity.startPreferenceFragment because the
- // title will not be updated correctly in the fragment
- // breadcrumb since it isn't inflated from the XML layout.
- mSettingsActivity.startPreferencePanel(
- TtsEngineSettingsFragment.class.getName(),
- args, 0, mEngineInfo.label, null, 0);
- }
- });
-
- if (mVoiceCheckData != null) {
- mSettingsIcon.setEnabled(mRadioButton.isChecked());
- }
}
public void setVoiceDataDetails(Intent data) {
mVoiceCheckData = data;
- // This might end up running before getView aboive, in which
- // case mSettingsIcon && mRadioButton will be null. In this case
- // getView will set the right values.
- if (mSettingsIcon != null && mRadioButton != null) {
- if (mRadioButton.isChecked()) {
- mSettingsIcon.setEnabled(true);
- } else {
- mSettingsIcon.setEnabled(false);
- mSettingsIcon.setAlpha(Utils.DISABLED_ALPHA);
- }
- }
}
private boolean shouldDisplayDataAlert() {
@@ -227,8 +155,6 @@
// Privileged engine, set it current
makeCurrentEngine(buttonView);
}
- } else {
- mSettingsIcon.setEnabled(false);
}
}
@@ -239,7 +165,6 @@
mSharedState.setCurrentChecked(current);
mSharedState.setCurrentKey(getKey());
callChangeListener(mSharedState.getCurrentKey());
- mSettingsIcon.setEnabled(true);
}
diff --git a/src/com/android/settings/tts/TtsEnginePreferenceFragment.java b/src/com/android/settings/tts/TtsEnginePreferenceFragment.java
new file mode 100644
index 0000000..e0ed8b7
--- /dev/null
+++ b/src/com/android/settings/tts/TtsEnginePreferenceFragment.java
@@ -0,0 +1,194 @@
+package com.android.settings.tts;
+
+import android.speech.tts.TextToSpeech;
+import com.android.settings.R;
+import android.os.Bundle;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import android.support.v7.preference.PreferenceCategory;
+import android.speech.tts.TtsEngines;
+import android.speech.tts.TextToSpeech.EngineInfo;
+import com.android.settings.SettingsActivity;
+import com.android.settings.tts.TtsEnginePreference.RadioButtonGroupState;
+import android.widget.Checkable;
+import android.util.Log;
+import static android.provider.Settings.Secure.TTS_DEFAULT_SYNTH;
+import com.android.settings.search.Indexable;
+import com.android.settings.search.BaseSearchIndexProvider;
+import android.content.Context;
+import android.provider.SearchIndexableResource;
+
+import java.util.List;
+import java.util.Arrays;
+
+public class TtsEnginePreferenceFragment extends SettingsPreferenceFragment //implements
+ implements RadioButtonGroupState, Indexable {
+ private static final String TAG = "TtsEnginePreferenceFragment";
+
+ private static final int VOICE_DATA_INTEGRITY_CHECK = 1977;
+
+ /** 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 PreferenceCategory mEnginePreferenceCategory;
+
+ private TextToSpeech mTts = null;
+ private TtsEngines mEnginesHelper = null;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.tts_engine_picker);
+
+ mEnginePreferenceCategory =
+ (PreferenceCategory) findPreference("tts_engine_preference_category");
+ mEnginesHelper = new TtsEngines(getActivity().getApplicationContext());
+
+ mTts = new TextToSpeech(getActivity().getApplicationContext(), null);
+
+ initSettings();
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.TTS_ENGINE_SETTINGS;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (mTts != null) {
+ mTts.shutdown();
+ mTts = null;
+ }
+ }
+
+ private void initSettings() {
+ if (mTts != null) {
+ mCurrentEngine = mTts.getCurrentEngine();
+ }
+
+ mEnginePreferenceCategory.removeAll();
+
+ SettingsActivity activity = (SettingsActivity) getActivity();
+
+ List<EngineInfo> engines = mEnginesHelper.getEngines();
+ for (EngineInfo engine : engines) {
+ TtsEnginePreference enginePref =
+ new TtsEnginePreference(getPrefContext(), engine, this, activity);
+ mEnginePreferenceCategory.addPreference(enginePref);
+ }
+ }
+
+ @Override
+ public Checkable getCurrentChecked() {
+ return mCurrentChecked;
+ }
+
+ @Override
+ public String getCurrentKey() {
+ return mCurrentEngine;
+ }
+
+ @Override
+ public void setCurrentChecked(Checkable current) {
+ mCurrentChecked = current;
+ }
+
+ /**
+ * 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);
+ }
+ };
+
+ private void updateDefaultEngine(String engine) {
+ Log.d(TAG, "Updating default synth to : " + engine);
+
+ // 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.
+ Log.i(TAG, "Shutting down current 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.
+ Log.i(TAG, "Updating engine : Attempting to connect to engine: " + engine);
+ mTts = new TextToSpeech(getActivity().getApplicationContext(), mUpdateListener, engine);
+ Log.i(TAG, "Success");
+ }
+
+ /**
+ * 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) {
+ Log.d(
+ TAG,
+ "Updating engine: Successfully bound to the engine: "
+ + mTts.getCurrentEngine());
+ android.provider.Settings.Secure.putString(
+ getContentResolver(), TTS_DEFAULT_SYNTH, mTts.getCurrentEngine());
+ } else {
+ 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(), null, mPreviousEngine);
+ }
+ mPreviousEngine = null;
+ }
+ }
+
+ @Override
+ public void setCurrentKey(String key) {
+ mCurrentEngine = key;
+ updateDefaultEngine(mCurrentEngine);
+ }
+
+ public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider() {
+ @Override
+ public List<SearchIndexableResource> getXmlResourcesToIndex(
+ Context context, boolean enabled) {
+ Log.i(TAG, "Indexing");
+ final SearchIndexableResource sir = new SearchIndexableResource(context);
+ sir.xmlResId = R.xml.tts_engine_picker;
+ return Arrays.asList(sir);
+ }
+ };
+}
diff --git a/src/com/android/settings/tts/TtsEngineSettingsFragment.java b/src/com/android/settings/tts/TtsEngineSettingsFragment.java
deleted file mode 100644
index 42222df..0000000
--- a/src/com/android/settings/tts/TtsEngineSettingsFragment.java
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.tts;
-
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.speech.tts.TextToSpeech;
-import android.speech.tts.TtsEngines;
-import android.support.v7.preference.ListPreference;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.Preference.OnPreferenceChangeListener;
-import android.support.v7.preference.Preference.OnPreferenceClickListener;
-import android.support.v7.preference.PreferenceScreen;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Pair;
-
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settings.R;
-import com.android.settings.SettingsPreferenceFragment;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-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 static final String STATE_KEY_LOCALE_ENTRIES = "locale_entries";
- private static final String STATE_KEY_LOCALE_ENTRY_VALUES= "locale_entry_values";
- private static final String STATE_KEY_LOCALE_VALUE = "locale_value";
-
- private static final int VOICE_DATA_INTEGRITY_CHECK = 1977;
-
- private TtsEngines mEnginesHelper;
- private ListPreference mLocalePreference;
- private Preference mEngineSettingsPreference;
- private Preference mInstallVoicesPreference;
- private Intent mEngineSettingsIntent;
- private Intent mVoiceDataDetails;
-
- private TextToSpeech mTts;
-
- private int mSelectedLocaleIndex = -1;
-
- private final TextToSpeech.OnInitListener mTtsInitListener = new TextToSpeech.OnInitListener() {
- @Override
- public void onInit(int status) {
- if (status != TextToSpeech.SUCCESS) {
- finishFragment();
- } else {
- getActivity().runOnUiThread(new Runnable() {
- @Override
- public void run() {
- mLocalePreference.setEnabled(true);
- }
- });
- }
- }
- };
-
- private final BroadcastReceiver mLanguagesChangedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- // Installed or uninstalled some data packs
- if (TextToSpeech.Engine.ACTION_TTS_DATA_INSTALLED.equals(intent.getAction())) {
- checkTtsData();
- }
- }
- };
-
- public TtsEngineSettingsFragment() {
- super();
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.TTS_ENGINE_SETTINGS;
- }
-
- @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);
-
- if (savedInstanceState == null) {
- mLocalePreference.setEnabled(false);
- mLocalePreference.setEntries(new CharSequence[0]);
- mLocalePreference.setEntryValues(new CharSequence[0]);
- } else {
- // Repopulate mLocalePreference with saved state. Will be updated later with
- // up-to-date values when checkTtsData() calls back with results.
- final CharSequence[] entries =
- savedInstanceState.getCharSequenceArray(STATE_KEY_LOCALE_ENTRIES);
- final CharSequence[] entryValues =
- savedInstanceState.getCharSequenceArray(STATE_KEY_LOCALE_ENTRY_VALUES);
- final CharSequence value =
- savedInstanceState.getCharSequence(STATE_KEY_LOCALE_VALUE);
-
- mLocalePreference.setEntries(entries);
- mLocalePreference.setEntryValues(entryValues);
- mLocalePreference.setValue(value != null ? value.toString() : null);
- mLocalePreference.setEnabled(entries.length > 0);
- }
-
- mVoiceDataDetails = getArguments().getParcelable(TtsEnginePreference.FRAGMENT_ARGS_VOICES);
-
- mTts = new TextToSpeech(getActivity().getApplicationContext(), mTtsInitListener,
- getEngineName());
-
- // Check if data packs changed
- checkTtsData();
-
- getActivity().registerReceiver(mLanguagesChangedReceiver,
- new IntentFilter(TextToSpeech.Engine.ACTION_TTS_DATA_INSTALLED));
- }
-
- @Override
- public void onDestroy() {
- getActivity().unregisterReceiver(mLanguagesChangedReceiver);
- mTts.shutdown();
- super.onDestroy();
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
-
- // Save the mLocalePreference values, so we can repopulate it with entries.
- outState.putCharSequenceArray(STATE_KEY_LOCALE_ENTRIES,
- mLocalePreference.getEntries());
- outState.putCharSequenceArray(STATE_KEY_LOCALE_ENTRY_VALUES,
- mLocalePreference.getEntryValues());
- outState.putCharSequence(STATE_KEY_LOCALE_VALUE,
- mLocalePreference.getValue());
- }
-
- private final void checkTtsData() {
- Intent intent = new Intent(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
- intent.setPackage(getEngineName());
- 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 + ")");
- }
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == VOICE_DATA_INTEGRITY_CHECK) {
- if (resultCode != TextToSpeech.Engine.CHECK_VOICE_DATA_FAIL) {
- updateVoiceDetails(data);
- } else {
- Log.e(TAG, "CheckVoiceData activity failed");
- }
- }
- }
-
- private void updateVoiceDetails(Intent data) {
- if (data == null){
- Log.e(TAG, "Engine failed voice data integrity check (null return)" +
- mTts.getCurrentEngine());
- return;
- }
- mVoiceDataDetails = data;
-
- if (DBG) Log.d(TAG, "Parsing voice data details, data: " + mVoiceDataDetails.toUri(0));
-
- final ArrayList<String> available = mVoiceDataDetails.getStringArrayListExtra(
- TextToSpeech.Engine.EXTRA_AVAILABLE_VOICES);
- final ArrayList<String> unavailable = mVoiceDataDetails.getStringArrayListExtra(
- TextToSpeech.Engine.EXTRA_UNAVAILABLE_VOICES);
-
- if (unavailable != null && unavailable.size() > 0) {
- mInstallVoicesPreference.setEnabled(true);
- } else {
- mInstallVoicesPreference.setEnabled(false);
- }
-
- if (available == null){
- Log.e(TAG, "TTS data check failed (available == null).");
- mLocalePreference.setEnabled(false);
- return;
- } else {
- updateDefaultLocalePref(available);
- }
- }
-
- private void updateDefaultLocalePref(ArrayList<String> availableLangs) {
- if (availableLangs == null || availableLangs.size() == 0) {
- mLocalePreference.setEnabled(false);
- return;
- }
- Locale currentLocale = null;
- if (!mEnginesHelper.isLocaleSetToDefaultForEngine(getEngineName())) {
- currentLocale = mEnginesHelper.getLocalePrefForEngine(getEngineName());
- }
-
- ArrayList<Pair<String, Locale>> entryPairs =
- new ArrayList<Pair<String, Locale>>(availableLangs.size());
- for (int i = 0; i < availableLangs.size(); i++) {
- Locale locale = mEnginesHelper.parseLocaleString(availableLangs.get(i));
- if (locale != null){
- entryPairs.add(new Pair<String, Locale>(
- locale.getDisplayName(), locale));
- }
- }
-
- // Sort it
- Collections.sort(entryPairs, new Comparator<Pair<String, Locale>>() {
- @Override
- public int compare(Pair<String, Locale> lhs, Pair<String, Locale> rhs) {
- return lhs.first.compareToIgnoreCase(rhs.first);
- }
- });
-
- // Get two arrays out of one of pairs
- mSelectedLocaleIndex = 0; // Will point to the R.string.tts_lang_use_system value
- CharSequence[] entries = new CharSequence[availableLangs.size()+1];
- CharSequence[] entryValues = new CharSequence[availableLangs.size()+1];
-
- entries[0] = getActivity().getString(R.string.tts_lang_use_system);
- entryValues[0] = "";
-
- int i = 1;
- for (Pair<String, Locale> entry : entryPairs) {
- if (entry.second.equals(currentLocale)) {
- mSelectedLocaleIndex = i;
- }
- entries[i] = entry.first;
- entryValues[i++] = entry.second.toString();
- }
-
- mLocalePreference.setEntries(entries);
- mLocalePreference.setEntryValues(entryValues);
- mLocalePreference.setEnabled(true);
- setLocalePreference(mSelectedLocaleIndex);
- }
-
- /** Set entry from entry table in mLocalePreference */
- private void setLocalePreference(int index) {
- if (index < 0) {
- mLocalePreference.setValue("");
- mLocalePreference.setSummary(R.string.tts_lang_not_selected);
- } else {
- mLocalePreference.setValueIndex(index);
- mLocalePreference.setSummary(mLocalePreference.getEntries()[index]);
- }
- }
-
- /**
- * 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.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) {
- String localeString = (String) newValue;
- updateLanguageTo((!TextUtils.isEmpty(localeString) ?
- mEnginesHelper.parseLocaleString(localeString) : null));
- return true;
- }
- return false;
- }
-
- private void updateLanguageTo(Locale locale) {
- int selectedLocaleIndex = -1;
- String localeString = (locale != null) ? locale.toString() : "";
- for (int i=0; i < mLocalePreference.getEntryValues().length; i++) {
- if (localeString.equalsIgnoreCase(mLocalePreference.getEntryValues()[i].toString())) {
- selectedLocaleIndex = i;
- break;
- }
- }
-
- if (selectedLocaleIndex == -1) {
- Log.w(TAG, "updateLanguageTo called with unknown locale argument");
- return;
- }
- mLocalePreference.setSummary(mLocalePreference.getEntries()[selectedLocaleIndex]);
- mSelectedLocaleIndex = selectedLocaleIndex;
-
- mEnginesHelper.updateLocalePrefForEngine(getEngineName(), locale);
-
- if (getEngineName().equals(mTts.getCurrentEngine())) {
- // Null locale means "use system default"
- mTts.setLanguage((locale != null) ? locale : Locale.getDefault());
- }
- }
-
- 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/tts/TtsSlidersFragment.java b/src/com/android/settings/tts/TtsSlidersFragment.java
new file mode 100644
index 0000000..7fdbd62
--- /dev/null
+++ b/src/com/android/settings/tts/TtsSlidersFragment.java
@@ -0,0 +1,207 @@
+package com.android.settings.tts;
+
+import android.speech.tts.TextToSpeech;
+import com.android.settings.R;
+import android.os.Bundle;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import android.util.Log;
+import com.android.settings.SeekBarPreference;
+import android.support.v7.preference.Preference;
+import android.content.ContentResolver;
+import com.android.settings.search.Indexable;
+import com.android.settings.search.BaseSearchIndexProvider;
+import android.content.Context;
+import android.provider.SearchIndexableResource;
+
+import java.util.List;
+import java.util.Arrays;
+
+import static android.provider.Settings.Secure.TTS_DEFAULT_PITCH;
+import static android.provider.Settings.Secure.TTS_DEFAULT_RATE;
+
+public class TtsSlidersFragment extends SettingsPreferenceFragment
+ implements Preference.OnPreferenceChangeListener,
+ Preference.OnPreferenceClickListener,
+ Indexable {
+ private static final String TAG = TtsSlidersFragment.class.getSimpleName();
+ private static final boolean DBG = false;
+
+ /** Preference key for the TTS pitch selection slider. */
+ private static final String KEY_DEFAULT_PITCH = "tts_default_pitch";
+
+ /** Preference key for the TTS rate selection slider. */
+ private static final String KEY_DEFAULT_RATE = "tts_default_rate";
+
+ /** Preference key for the TTS reset speech rate preference. */
+ private static final String KEY_RESET_SPEECH_RATE = "reset_speech_rate";
+
+ /** Preference key for the TTS reset speech pitch preference. */
+ private static final String KEY_RESET_SPEECH_PITCH = "reset_speech_pitch";
+
+ /**
+ * Speech rate value. This value should be kept in sync with the max value set in tts_settings
+ * xml.
+ */
+ private static final int MAX_SPEECH_RATE = 600;
+
+ private static final int MIN_SPEECH_RATE = 10;
+
+ /**
+ * Speech pitch value. TTS pitch value varies from 25 to 400, where 100 is the value for normal
+ * pitch. The max pitch value is set to 400, based on feedback from users and the GoogleTTS
+ * pitch variation range. The range for pitch is not set in stone and should be readjusted based
+ * on user need. This value should be kept in sync with the max value set in tts_settings xml.
+ */
+ private static final int MAX_SPEECH_PITCH = 400;
+
+ private static final int MIN_SPEECH_PITCH = 25;
+
+ private int mDefaultPitch = TextToSpeech.Engine.DEFAULT_PITCH;
+ private int mDefaultRate = TextToSpeech.Engine.DEFAULT_RATE;
+
+ private SeekBarPreference mDefaultPitchPref;
+ private SeekBarPreference mDefaultRatePref;
+ private Preference mResetSpeechRate;
+ private Preference mResetSpeechPitch;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.tts_sliders);
+
+ mResetSpeechRate = findPreference(KEY_RESET_SPEECH_RATE);
+ mResetSpeechRate.setOnPreferenceClickListener(this);
+ mResetSpeechPitch = findPreference(KEY_RESET_SPEECH_PITCH);
+ mResetSpeechPitch.setOnPreferenceClickListener(this);
+
+ mDefaultPitchPref = (SeekBarPreference) findPreference(KEY_DEFAULT_PITCH);
+ mDefaultRatePref = (SeekBarPreference) findPreference(KEY_DEFAULT_RATE);
+
+ initSettings();
+ }
+
+ private void initSettings() {
+ final ContentResolver resolver = getContentResolver();
+ // Set up the default rate and pitch.
+ mDefaultRate =
+ android.provider.Settings.Secure.getInt(
+ resolver, TTS_DEFAULT_RATE, TextToSpeech.Engine.DEFAULT_RATE);
+ mDefaultPitch =
+ android.provider.Settings.Secure.getInt(
+ resolver, TTS_DEFAULT_PITCH, TextToSpeech.Engine.DEFAULT_PITCH);
+
+ mDefaultRatePref.setProgress(getSeekBarProgressFromValue(KEY_DEFAULT_RATE, mDefaultRate));
+ mDefaultRatePref.setOnPreferenceChangeListener(this);
+ mDefaultRatePref.setMax(getSeekBarProgressFromValue(KEY_DEFAULT_RATE, MAX_SPEECH_RATE));
+
+ mDefaultPitchPref.setProgress(
+ getSeekBarProgressFromValue(KEY_DEFAULT_PITCH, mDefaultPitch));
+ mDefaultPitchPref.setOnPreferenceChangeListener(this);
+ mDefaultPitchPref.setMax(getSeekBarProgressFromValue(KEY_DEFAULT_PITCH, MAX_SPEECH_PITCH));
+ }
+
+ /**
+ * The minimum speech pitch/rate value should be > 0 but the minimum value of a seekbar in
+ * android is fixed at 0. Therefore, we increment the seekbar progress with MIN_SPEECH_VALUE so
+ * that the minimum seekbar progress value is MIN_SPEECH_PITCH/RATE. SPEECH_VALUE =
+ * MIN_SPEECH_VALUE + SEEKBAR_PROGRESS
+ */
+ private int getValueFromSeekBarProgress(String preferenceKey, int progress) {
+ if (preferenceKey.equals(KEY_DEFAULT_RATE)) {
+ return MIN_SPEECH_RATE + progress;
+ } else if (preferenceKey.equals(KEY_DEFAULT_PITCH)) {
+ return MIN_SPEECH_PITCH + progress;
+ }
+ return progress;
+ }
+
+ /**
+ * Since we are appending the MIN_SPEECH value to the speech seekbar progress, the speech
+ * seekbar progress should be set to (speechValue - MIN_SPEECH value).
+ */
+ private int getSeekBarProgressFromValue(String preferenceKey, int value) {
+ if (preferenceKey.equals(KEY_DEFAULT_RATE)) {
+ return value - MIN_SPEECH_RATE;
+ } else if (preferenceKey.equals(KEY_DEFAULT_PITCH)) {
+ return value - MIN_SPEECH_PITCH;
+ }
+ return value;
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object objValue) {
+ if (KEY_DEFAULT_RATE.equals(preference.getKey())) {
+ updateSpeechRate((Integer) objValue);
+ } else if (KEY_DEFAULT_PITCH.equals(preference.getKey())) {
+ updateSpeechPitchValue((Integer) objValue);
+ }
+ return true;
+ }
+
+ /** Called when mPlayExample, mResetSpeechRate or mResetSpeechPitch is clicked. */
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ if (preference == mResetSpeechRate) {
+ int speechRateSeekbarProgress =
+ getSeekBarProgressFromValue(KEY_DEFAULT_RATE, TextToSpeech.Engine.DEFAULT_RATE);
+ mDefaultRatePref.setProgress(speechRateSeekbarProgress);
+ updateSpeechRate(speechRateSeekbarProgress);
+ return true;
+ } else if (preference == mResetSpeechPitch) {
+ int pitchSeekbarProgress =
+ getSeekBarProgressFromValue(
+ KEY_DEFAULT_PITCH, TextToSpeech.Engine.DEFAULT_PITCH);
+ mDefaultPitchPref.setProgress(pitchSeekbarProgress);
+ updateSpeechPitchValue(pitchSeekbarProgress);
+ return true;
+ }
+ return false;
+ }
+
+ private void updateSpeechRate(int speechRateSeekBarProgress) {
+ mDefaultRate = getValueFromSeekBarProgress(KEY_DEFAULT_RATE, speechRateSeekBarProgress);
+ try {
+ android.provider.Settings.Secure.putInt(
+ getContentResolver(), TTS_DEFAULT_RATE, mDefaultRate);
+ 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;
+ }
+
+ private void updateSpeechPitchValue(int speechPitchSeekBarProgress) {
+ mDefaultPitch = getValueFromSeekBarProgress(KEY_DEFAULT_PITCH, speechPitchSeekBarProgress);
+ try {
+ android.provider.Settings.Secure.putInt(
+ getContentResolver(), TTS_DEFAULT_PITCH, mDefaultPitch);
+ if (DBG) Log.d(TAG, "TTS default pitch changed, now" + mDefaultPitch);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "could not persist default TTS pitch setting", e);
+ }
+ return;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.TTS_SLIDERS;
+ }
+
+ public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider() {
+ @Override
+ public List<SearchIndexableResource> getXmlResourcesToIndex(
+ Context context, boolean enabled) {
+ Log.i(TAG, "Indexing");
+ final SearchIndexableResource sir = new SearchIndexableResource(context);
+ sir.xmlResId = R.xml.tts_sliders;
+ return Arrays.asList(sir);
+ }
+ };
+}
diff --git a/src/com/android/settings/webview/WebViewAppListAdapter.java b/src/com/android/settings/webview/WebViewAppListAdapter.java
index 85dbf7c..4c36a47 100644
--- a/src/com/android/settings/webview/WebViewAppListAdapter.java
+++ b/src/com/android/settings/webview/WebViewAppListAdapter.java
@@ -16,8 +16,10 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.RemoteException;
+import android.graphics.Color;
import android.support.annotation.VisibleForTesting;
import android.view.LayoutInflater;
import android.view.View;
@@ -36,6 +38,7 @@
*/
class WebViewAppListAdapter extends ArrayAdapter<WebViewApplicationInfo> {
private final LayoutInflater mInflater;
+ private final String mCurrentWebViewPackageName;
public WebViewAppListAdapter(Context context,
WebViewUpdateServiceWrapper webviewUpdateServiceWrapper) {
@@ -53,6 +56,10 @@
packageInfoList.add(info);
}
addAll(packageInfoList);
+
+ PackageInfo currentWebViewPackage = webviewUpdateServiceWrapper.getCurrentWebViewPackage();
+ mCurrentWebViewPackageName =
+ currentWebViewPackage == null ? null : currentWebViewPackage.packageName;
}
@Override
@@ -80,6 +87,11 @@
holder.disabled.setVisibility(View.GONE);
// Only allow a package to be chosen if it is enabled and installed for all users.
convertView.setEnabled(isEnabled(position));
+ if (info.info.packageName.equals(mCurrentWebViewPackageName)) {
+ convertView.setBackgroundColor(Color.GRAY);
+ } else {
+ convertView.setBackgroundColor(Color.WHITE);
+ }
return convertView;
}
diff --git a/src/com/android/settings/webview/WebViewAppPreferenceController.java b/src/com/android/settings/webview/WebViewAppPreferenceController.java
index eb5467a..cfb358e 100644
--- a/src/com/android/settings/webview/WebViewAppPreferenceController.java
+++ b/src/com/android/settings/webview/WebViewAppPreferenceController.java
@@ -73,9 +73,10 @@
* Handle the return-value from the WebViewAppPicker Activity.
*/
public void onActivityResult(int resultCode, Intent data) {
- if (resultCode == Activity.RESULT_OK) {
- updateState(null);
- }
+ // Update the preference summary no matter whether we succeeded to change the webview
+ // implementation correctly - we might have changed implementation to one the user did not
+ // choose.
+ updateState(null);
}
private String getCurrentWebViewPackageLabel(Context context) {
diff --git a/tests/robotests/src/com/android/settings/webview/WebViewAppPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/webview/WebViewAppPreferenceControllerTest.java
index c16bd1f..e0a32a4 100644
--- a/tests/robotests/src/com/android/settings/webview/WebViewAppPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/webview/WebViewAppPreferenceControllerTest.java
@@ -70,7 +70,7 @@
verify(controller, times(1)).updateState(any());
}
- @Test public void testOnActivityResultWithFailureDoesNothing() {
+ @Test public void testOnActivityResultWithFailure() {
WebViewUpdateServiceWrapper wvusWrapper = mock(WebViewUpdateServiceWrapper.class);
WebViewAppPreferenceController controller =
@@ -78,6 +78,6 @@
controller.displayPreference(mPreferenceScreen); // Makes sure Preference is non-null
controller.onActivityResult(Activity.RESULT_CANCELED, new Intent(DEFAULT_PACKAGE_NAME));
- verify(controller, never()).updateState(any());
+ verify(controller, times(1)).updateState(any());
}
}