New iteration of the Text-to-Speech settings.

- Moves speech rate and pitch back to first page.
- Voice selection is now expected to happen in Engine settings
- Play/reset buttons are now actual buttons.

Test: mmma packages/apps/Settings
Change-Id: I917298473ec473e11eccededee1cb948b0afe911
This commit is contained in:
Niels Egberts
2017-03-20 19:57:17 +00:00
parent 92ae1f2d8e
commit 46f38575ec
7 changed files with 263 additions and 339 deletions

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2016 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:gravity="bottom"
android:paddingTop="4dp"
android:paddingStart="68dp"
android:paddingEnd="8dp"
android:orientation="horizontal">
<Button
android:id="@+id/tts_play_button"
style="@style/android:Widget.Material.Button.Colored"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingEnd="8dp"
android:text="@string/tts_play"/>
<Button
android:id="@+id/tts_reset_button"
style="@style/android:Widget.Material.Button"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingStart="8dp"
android:text="@string/tts_reset"/>
</LinearLayout>

View File

@@ -4725,10 +4725,11 @@
<!-- [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>
<!-- 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>
<!-- Name for button that resets speech rate and pitch for synthesized voice to default values in the text to speech settings.-->
<string name="tts_reset">Reset</string>
<!-- Name for buttont hat plays a sample of the currently selected text-to-speech engine. -->
<string name="tts_play">Play</string>
<!-- Power Control Widget -->
<string name="gadget_title">Power control</string>

View File

@@ -17,7 +17,6 @@
<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"/>
<PreferenceCategory android:key="tts_engine_preference_category"/>
</PreferenceScreen>

View File

@@ -14,53 +14,47 @@
limitations under the License.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/tts_settings_title">
<PreferenceCategory android:key="tts_engine_section"
android:title="@string/tts_engine_section_title">
<PreferenceCategory android:key="tts_engine_section">
<com.android.settingslib.RestrictedPreference android:key="tts_engine_preference"
<com.android.settings.widget.GearPreference
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">
<com.android.settingslib.RestrictedPreference
android:key="tts_sliders"
android:title="@string/tts_sliders_title"
android:fragment="com.android.settings.tts.TtsSlidersFragment"/>
<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"
android:title="@string/tts_play_example_title"
android:summary="@string/tts_play_example_summary" />
</PreferenceCategory>
<PreferenceCategory android:key="tts_general_section">
<!-- 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.settings.applications.LayoutPreference
android:key="action_buttons"
android:layout="@layout/tts_action_buttons"
android:selectable="false"/>
<Preference android:key="tts_status"
android:enabled="false"
android:shouldDisableView="false"
android:persistent="false"
android:title="@string/tts_status_title"/>
</PreferenceCategory>
</PreferenceScreen>

View File

@@ -73,7 +73,6 @@ 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.wallpaper.WallpaperTypeSettings;
import com.android.settings.wifi.ConfigureWifiSettings;
@@ -171,7 +170,6 @@ public final class SearchIndexableResources {
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() {

View File

@@ -30,13 +30,18 @@ import android.support.v7.preference.Preference;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.view.View;
import java.util.Comparator;
import java.util.Collections;
import com.android.settings.applications.LayoutPreference;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.SeekBarPreference;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.widget.GearPreference;
import android.widget.Button;
import java.util.ArrayList;
import java.util.HashMap;
@@ -46,11 +51,14 @@ import java.util.MissingResourceException;
import java.util.Objects;
import java.util.Set;
import static android.provider.Settings.Secure.TTS_DEFAULT_SYNTH;
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;
public class TextToSpeechSettings extends SettingsPreferenceFragment
implements Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener {
implements Preference.OnPreferenceChangeListener,
View.OnClickListener,
GearPreference.OnGearClickListener {
private static final String STATE_KEY_LOCALE_ENTRIES = "locale_entries";
private static final String STATE_KEY_LOCALE_ENTRY_VALUES = "locale_entry_values";
@@ -59,11 +67,20 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment
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 pitch selection slider. */
private static final String KEY_DEFAULT_PITCH = "tts_default_pitch";
/** Preference key for the TTS status field. */
private static final String KEY_STATUS = "tts_status";
/** Preference key for the TTS rate selection slider. */
private static final String KEY_DEFAULT_RATE = "tts_default_rate";
/** Engine picker. */
private static final String KEY_TTS_ENGINE_PREFERENCE = "tts_engine_preference";
/** Locale picker. */
private static final String KEY_ENGINE_LOCALE = "tts_default_lang";
/** Play/Reset buttons container. */
private static final String KEY_ACTION_BUTTONS = "action_buttons";
/**
* These look like birth years, but they aren't mine. I'm much younger than this.
@@ -71,13 +88,32 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment
private static final int GET_SAMPLE_TEXT = 1983;
private static final int VOICE_DATA_INTEGRITY_CHECK = 1977;
private Preference mPlayExample;
private Preference mEngineStatus;
/**
* 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;
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";
/**
* 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 SeekBarPreference mDefaultPitchPref;
private SeekBarPreference mDefaultRatePref;
private Button mResetButton;
private Button mPlayButton;
private LayoutPreference mActionButtons;
private int mDefaultPitch = TextToSpeech.Engine.DEFAULT_PITCH;
private int mDefaultRate = TextToSpeech.Engine.DEFAULT_RATE;
private int mSelectedLocaleIndex = -1;
@@ -90,7 +126,6 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment
private String mSampleText = null;
private ListPreference mLocalePreference;
private Preference mEngineSettingsPreference;
private Preference mInstallVoicesPreference;
/**
@@ -129,15 +164,21 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment
getActivity().setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
mPlayExample = findPreference(KEY_PLAY_EXAMPLE);
mPlayExample.setOnPreferenceClickListener(this);
mPlayExample.setEnabled(false);
mEnginesHelper = new TtsEngines(getActivity().getApplicationContext());
mLocalePreference = (ListPreference) findPreference(KEY_ENGINE_LOCALE);
mLocalePreference.setOnPreferenceChangeListener(this);
mDefaultPitchPref = (SeekBarPreference) findPreference(KEY_DEFAULT_PITCH);
mDefaultRatePref = (SeekBarPreference) findPreference(KEY_DEFAULT_RATE);
mActionButtons = (LayoutPreference) findPreference(KEY_ACTION_BUTTONS);
mPlayButton = (Button) mActionButtons.findViewById(R.id.tts_play_button);
mPlayButton.setOnClickListener(this);
mPlayButton.setEnabled(false);
mResetButton = (Button) mActionButtons.findViewById(R.id.tts_reset_button);
mResetButton.setOnClickListener(this);
if (savedInstanceState == null) {
mLocalePreference.setEnabled(false);
mLocalePreference.setEntries(new CharSequence[0]);
@@ -157,15 +198,6 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment
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);
setTtsUtteranceProgressListener();
@@ -236,9 +268,27 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment
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.setPitch(android.provider.Settings.Secure.getInt(resolver, TTS_DEFAULT_PITCH, TextToSpeech.Engine.DEFAULT_PITCH)/100.0f);
mTts.setSpeechRate(mDefaultRate / 100.0f);
mTts.setPitch(mDefaultPitch / 100.0f);
}
SettingsActivity activity = null;
@@ -251,14 +301,11 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment
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);
}
Preference mEnginePreference = findPreference("tts_engine_preference");
Preference mEnginePreference = findPreference(KEY_TTS_ENGINE_PREFERENCE);
((GearPreference) mEnginePreference).setOnGearClickListener(this);
mEnginePreference.setSummary(info.label);
}
@@ -266,8 +313,34 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment
}
/**
* Called when the TTS engine is initialized.
* 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.");
@@ -291,7 +364,6 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment
if (defaultLocale == null) {
Log.e(TAG, "Failed to get default language from engine " + mCurrentEngine);
updateWidgetState(false);
updateEngineStatus(R.string.tts_status_not_supported);
return;
}
@@ -335,7 +407,6 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment
}
} catch (MissingResourceException e) {
if (DBG) Log.wtf(TAG, "MissingResourceException", e);
updateEngineStatus(R.string.tts_status_not_supported);
updateWidgetState(false);
return false;
}
@@ -345,15 +416,9 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment
defaultAvailable == TextToSpeech.LANG_MISSING_DATA ||
notInAvailableLangauges) {
if (DBG) Log.d(TAG, "Default locale for this TTS engine is not supported.");
updateEngineStatus(R.string.tts_status_not_supported);
updateWidgetState(false);
return false;
} else {
if (isNetworkRequiredForSynthesis()) {
updateEngineStatus(R.string.tts_status_requires_network);
} else {
updateEngineStatus(R.string.tts_status_ok);
}
updateWidgetState(true);
return true;
}
@@ -409,12 +474,6 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment
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;
@@ -545,7 +604,11 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment
@Override
public boolean onPreferenceChange(Preference preference, Object objValue) {
if (preference == mLocalePreference) {
if (KEY_DEFAULT_RATE.equals(preference.getKey())) {
updateSpeechRate((Integer) objValue);
} else if (KEY_DEFAULT_PITCH.equals(preference.getKey())) {
updateSpeechPitchValue((Integer) objValue);
} else if (preference == mLocalePreference) {
String localeString = (String) objValue;
updateLanguageTo(
(!TextUtils.isEmpty(localeString)
@@ -580,50 +643,68 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment
mTts.setLanguage((locale != null) ? locale : Locale.getDefault());
}
/**
* 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.
*/
/** Called when mPlayButton, mResetButton is clicked. */
@Override
public boolean onPreferenceClick(Preference preference) {
if (preference == mPlayExample) {
public void onClick(View v) {
switch (v.getId()) {
case R.id.tts_play_button:
// Play button.
// Get the sample text from the TTS engine; onActivityResult will do
// the actual speaking
speakSampleText();
return true;
} else if (preference == mInstallVoicesPreference) {
installVoiceData();
return true;
break;
case R.id.tts_reset_button:
// Reset button.
int speechRateSeekbarProgress =
getSeekBarProgressFromValue(
KEY_DEFAULT_RATE, TextToSpeech.Engine.DEFAULT_RATE);
mDefaultRatePref.setProgress(speechRateSeekbarProgress);
updateSpeechRate(speechRateSeekbarProgress);
int pitchSeekbarProgress =
getSeekBarProgressFromValue(
KEY_DEFAULT_PITCH, TextToSpeech.Engine.DEFAULT_PITCH);
mDefaultPitchPref.setProgress(pitchSeekbarProgress);
updateSpeechPitchValue(pitchSeekbarProgress);
break;
default:
break;
}
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);
mEngineStatus.setEnabled(enable);
}
private void updateEngineStatus(int resourceId) {
Locale locale = mCurrentDefaultLocale;
if (locale == null) {
locale = Locale.getDefault();
}
mEngineStatus.setSummary(getString(resourceId, locale.getDisplayName()));
mPlayButton.setEnabled(enable);
mDefaultRatePref.setEnabled(enable);
mDefaultPitchPref.setEnabled(enable);
}
private void displayNetworkAlert() {
@@ -677,4 +758,14 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment
getSampleText();
}
}
@Override
public void onGearClick(GearPreference p) {
if (KEY_TTS_ENGINE_PREFERENCE.equals(p.getKey())) {
EngineInfo info = mEnginesHelper.getEngineInfo(mCurrentEngine);
final Intent settingsIntent = mEnginesHelper.getSettingsIntent(info.name);
startActivity(settingsIntent);
}
}
}

View File

@@ -1,207 +0,0 @@
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);
}
};
}