Move settings to their new location according to ux spec.
This change doesn't add or remove any functionality. Additionally, make the settings searchable. Test: mmma packages/apps/Settings + manual testing Change-Id: Id3e24fd52b49b7373b4f247241cc52f61ffe169e
This commit is contained in:
@@ -31,17 +31,4 @@
|
|||||||
android:maxLines="2"
|
android:maxLines="2"
|
||||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||||
android:ellipsize="marquee"/>
|
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>
|
</LinearLayout>
|
||||||
|
@@ -4624,9 +4624,20 @@
|
|||||||
behalf. It comes from the <xliff:g id="voice_input_service_app_name">%s</xliff:g>
|
behalf. It comes from the <xliff:g id="voice_input_service_app_name">%s</xliff:g>
|
||||||
application. Enable the use of this service?</string>
|
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>
|
<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>
|
<string name="tts_reset_speech_rate_summary">Reset the speed at which the text is spoken to normal.</string>
|
||||||
|
|
||||||
<!-- Power Control Widget -->
|
<!-- Power Control Widget -->
|
||||||
|
23
res/xml/tts_engine_picker.xml
Normal file
23
res/xml/tts_engine_picker.xml
Normal file
@@ -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>
|
@@ -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>
|
|
@@ -17,38 +17,40 @@
|
|||||||
<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">
|
android:title="@string/tts_settings_title">
|
||||||
|
|
||||||
<!-- The contents of this category are filled in by the Java code
|
<PreferenceCategory android:key="tts_engine_section"
|
||||||
based on the list of available engines. -->
|
android:title="@string/tts_engine_section_title">
|
||||||
<PreferenceCategory android:key="tts_engine_preference_section"
|
|
||||||
android:title="@string/tts_engine_preference_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"
|
<PreferenceCategory android:key="tts_general_section"
|
||||||
android:title="@string/tts_general_section_title">
|
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
|
<com.android.settingslib.RestrictedPreference
|
||||||
android:key="tts_default_pitch"
|
android:key="tts_sliders"
|
||||||
android:title="@string/tts_default_pitch_title"
|
android:title="@string/tts_sliders_title"
|
||||||
android:summary="@string/tts_default_pitch_summary"
|
android:fragment="com.android.settings.tts.TtsSlidersFragment"/>
|
||||||
android:defaultValue="100"
|
|
||||||
android:max="400"/>
|
|
||||||
|
|
||||||
<Preference android:key="reset_speech_rate"
|
<ListPreference
|
||||||
android:persistent="false"
|
android:key="tts_default_lang"
|
||||||
android:title="@string/tts_reset_speech_rate_title"
|
android:title="@string/tts_default_lang_title"
|
||||||
android:summary="@string/tts_reset_speech_rate_summary" />
|
android:summary="@string/tts_default_lang_summary"
|
||||||
|
android:persistent="false" />
|
||||||
<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" />
|
|
||||||
|
|
||||||
<Preference android:key="tts_play_example"
|
<Preference android:key="tts_play_example"
|
||||||
android:persistent="false"
|
android:persistent="false"
|
||||||
|
46
res/xml/tts_sliders.xml
Normal file
46
res/xml/tts_sliders.xml
Normal file
@@ -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>
|
@@ -72,6 +72,8 @@ import com.android.settings.notification.ZenModeVisualInterruptionSettings;
|
|||||||
import com.android.settings.print.PrintSettingsFragment;
|
import com.android.settings.print.PrintSettingsFragment;
|
||||||
import com.android.settings.sim.SimSettings;
|
import com.android.settings.sim.SimSettings;
|
||||||
import com.android.settings.system.SystemDashboardFragment;
|
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.users.UserSettings;
|
||||||
import com.android.settings.wifi.AdvancedWifiSettings;
|
import com.android.settings.wifi.AdvancedWifiSettings;
|
||||||
import com.android.settings.wifi.ConfigureWifiSettings;
|
import com.android.settings.wifi.ConfigureWifiSettings;
|
||||||
@@ -167,6 +169,9 @@ public final class SearchIndexableResources {
|
|||||||
addIndex(ConnectedDeviceDashboardFragment.class, NO_DATA_RES_ID, R.drawable.ic_bt_laptop);
|
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(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(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() {
|
private SearchIndexableResources() {
|
||||||
|
@@ -16,29 +16,27 @@
|
|||||||
|
|
||||||
package com.android.settings.tts;
|
package com.android.settings.tts;
|
||||||
|
|
||||||
|
import android.support.v7.preference.ListPreference;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.Settings.SettingNotFoundException;
|
|
||||||
import android.speech.tts.TextToSpeech;
|
import android.speech.tts.TextToSpeech;
|
||||||
import android.speech.tts.TextToSpeech.EngineInfo;
|
import android.speech.tts.TextToSpeech.EngineInfo;
|
||||||
import android.speech.tts.TtsEngines;
|
import android.speech.tts.TtsEngines;
|
||||||
import android.speech.tts.UtteranceProgressListener;
|
import android.speech.tts.UtteranceProgressListener;
|
||||||
import android.support.v14.preference.SwitchPreference;
|
|
||||||
import android.support.v7.preference.Preference;
|
import android.support.v7.preference.Preference;
|
||||||
import android.support.v7.preference.PreferenceCategory;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
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.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.SeekBarPreference;
|
|
||||||
import com.android.settings.SettingsActivity;
|
import com.android.settings.SettingsActivity;
|
||||||
import com.android.settings.SettingsPreferenceFragment;
|
import com.android.settings.SettingsPreferenceFragment;
|
||||||
import com.android.settings.tts.TtsEnginePreference.RadioButtonGroupState;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -48,13 +46,15 @@ import java.util.MissingResourceException;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
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_SYNTH;
|
||||||
|
import static android.provider.Settings.Secure.TTS_DEFAULT_PITCH;
|
||||||
|
|
||||||
public class TextToSpeechSettings extends SettingsPreferenceFragment implements
|
public class TextToSpeechSettings extends SettingsPreferenceFragment
|
||||||
Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener,
|
implements Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener {
|
||||||
RadioButtonGroupState {
|
|
||||||
|
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 String TAG = "TextToSpeechSettings";
|
||||||
private static final boolean DBG = false;
|
private static final boolean DBG = false;
|
||||||
@@ -62,84 +62,37 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment implements
|
|||||||
/** Preference key for the "play TTS example" preference. */
|
/** Preference key for the "play TTS example" preference. */
|
||||||
private static final String KEY_PLAY_EXAMPLE = "tts_play_example";;
|
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. */
|
/** Preference key for the TTS status field. */
|
||||||
private static final String KEY_STATUS = "tts_status";
|
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.
|
* 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 GET_SAMPLE_TEXT = 1983;
|
||||||
private static final int VOICE_DATA_INTEGRITY_CHECK = 1977;
|
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 mPlayExample;
|
||||||
private Preference mEngineStatus;
|
private Preference mEngineStatus;
|
||||||
|
|
||||||
private int mDefaultPitch = TextToSpeech.Engine.DEFAULT_PITCH;
|
|
||||||
private int mDefaultRate = TextToSpeech.Engine.DEFAULT_RATE;
|
|
||||||
|
|
||||||
/**
|
private static final String KEY_ENGINE_LOCALE = "tts_default_lang";
|
||||||
* The currently selected engine.
|
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;
|
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 TextToSpeech mTts = null;
|
||||||
private TtsEngines mEnginesHelper = null;
|
private TtsEngines mEnginesHelper = null;
|
||||||
|
|
||||||
private String mSampleText = 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.
|
* Default locale used by selected TTS engine, null if not connected to any engine.
|
||||||
*/
|
*/
|
||||||
@@ -164,18 +117,6 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment implements
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
@Override
|
||||||
public int getMetricsCategory() {
|
public int getMetricsCategory() {
|
||||||
return MetricsEvent.TTS_TEXT_TO_SPEECH;
|
return MetricsEvent.TTS_TEXT_TO_SPEECH;
|
||||||
@@ -192,21 +133,40 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment implements
|
|||||||
mPlayExample.setOnPreferenceClickListener(this);
|
mPlayExample.setOnPreferenceClickListener(this);
|
||||||
mPlayExample.setEnabled(false);
|
mPlayExample.setEnabled(false);
|
||||||
|
|
||||||
mResetSpeechRate = findPreference(KEY_RESET_SPEECH_RATE);
|
mEnginesHelper = new TtsEngines(getActivity().getApplicationContext());
|
||||||
mResetSpeechRate.setOnPreferenceClickListener(this);
|
|
||||||
mResetSpeechPitch = findPreference(KEY_RESET_SPEECH_PITCH);
|
|
||||||
mResetSpeechPitch.setOnPreferenceClickListener(this);
|
|
||||||
|
|
||||||
mEnginePreferenceCategory = (PreferenceCategory) findPreference(
|
mLocalePreference = (ListPreference) findPreference(KEY_ENGINE_LOCALE);
|
||||||
KEY_ENGINE_PREFERENCE_SECTION);
|
mLocalePreference.setOnPreferenceChangeListener(this);
|
||||||
mDefaultPitchPref = (SeekBarPreference) findPreference(KEY_DEFAULT_PITCH);
|
|
||||||
mDefaultRatePref = (SeekBarPreference) findPreference(KEY_DEFAULT_RATE);
|
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);
|
mEngineStatus = findPreference(KEY_STATUS);
|
||||||
updateEngineStatus(R.string.tts_status_checking);
|
updateEngineStatus(R.string.tts_status_checking);
|
||||||
|
|
||||||
mTts = new TextToSpeech(getActivity().getApplicationContext(), mInitListener);
|
mTts = new TextToSpeech(getActivity().getApplicationContext(), mInitListener);
|
||||||
mEnginesHelper = new TtsEngines(getActivity().getApplicationContext());
|
|
||||||
|
|
||||||
setTtsUtteranceProgressListener();
|
setTtsUtteranceProgressListener();
|
||||||
initSettings();
|
initSettings();
|
||||||
@@ -222,6 +182,23 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment implements
|
|||||||
if (mTts == null || mCurrentDefaultLocale == null) {
|
if (mTts == null || mCurrentDefaultLocale == null) {
|
||||||
return;
|
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();
|
Locale ttsDefaultLocale = mTts.getDefaultLanguage();
|
||||||
if (mCurrentDefaultLocale != null && !mCurrentDefaultLocale.equals(ttsDefaultLocale)) {
|
if (mCurrentDefaultLocale != null && !mCurrentDefaultLocale.equals(ttsDefaultLocale)) {
|
||||||
updateWidgetState(false);
|
updateWidgetState(false);
|
||||||
@@ -259,26 +236,9 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment implements
|
|||||||
private void initSettings() {
|
private void initSettings() {
|
||||||
final ContentResolver resolver = getContentResolver();
|
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) {
|
if (mTts != null) {
|
||||||
mCurrentEngine = mTts.getCurrentEngine();
|
mCurrentEngine = mTts.getCurrentEngine();
|
||||||
mTts.setSpeechRate(mDefaultRate/100.0f);
|
mTts.setPitch(android.provider.Settings.Secure.getInt(resolver, TTS_DEFAULT_PITCH, TextToSpeech.Engine.DEFAULT_PITCH)/100.0f);
|
||||||
mTts.setPitch(mDefaultPitch/100.0f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsActivity activity = null;
|
SettingsActivity activity = null;
|
||||||
@@ -289,46 +249,22 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment implements
|
|||||||
"Settings");
|
"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();
|
Preference mEnginePreference = findPreference("tts_engine_preference");
|
||||||
for (EngineInfo engine : engines) {
|
mEnginePreference.setSummary(info.label);
|
||||||
TtsEnginePreference enginePref = new TtsEnginePreference(getPrefContext(), engine,
|
|
||||||
this, activity);
|
|
||||||
mEnginePreferenceCategory.addPreference(enginePref);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
checkVoiceData(mCurrentEngine);
|
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.
|
* Called when the TTS engine is initialized.
|
||||||
*/
|
*/
|
||||||
@@ -336,6 +272,14 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment implements
|
|||||||
if (status == TextToSpeech.SUCCESS) {
|
if (status == TextToSpeech.SUCCESS) {
|
||||||
if (DBG) Log.d(TAG, "TTS engine for settings screen initialized.");
|
if (DBG) Log.d(TAG, "TTS engine for settings screen initialized.");
|
||||||
checkDefaultLocale();
|
checkDefaultLocale();
|
||||||
|
getActivity()
|
||||||
|
.runOnUiThread(
|
||||||
|
new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
mLocalePreference.setEnabled(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
if (DBG) Log.d(TAG, "TTS engine for settings screen failed to initialize successfully.");
|
if (DBG) Log.d(TAG, "TTS engine for settings screen failed to initialize successfully.");
|
||||||
updateWidgetState(false);
|
updateWidgetState(false);
|
||||||
@@ -452,9 +396,88 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment implements
|
|||||||
onSampleTextReceived(resultCode, data);
|
onSampleTextReceived(resultCode, data);
|
||||||
} else if (requestCode == VOICE_DATA_INTEGRITY_CHECK) {
|
} else if (requestCode == VOICE_DATA_INTEGRITY_CHECK) {
|
||||||
onVoiceDataIntegrityCheckDone(data);
|
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() {
|
private String getDefaultSampleString() {
|
||||||
if (mTts != null && mTts.getLanguage() != null) {
|
if (mTts != null && mTts.getLanguage() != null) {
|
||||||
try {
|
try {
|
||||||
@@ -522,17 +545,59 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceChange(Preference preference, Object objValue) {
|
public boolean onPreferenceChange(Preference preference, Object objValue) {
|
||||||
if (KEY_DEFAULT_RATE.equals(preference.getKey())) {
|
if (preference == mLocalePreference) {
|
||||||
updateSpeechRate((Integer) objValue);
|
String localeString = (String) objValue;
|
||||||
} else if (KEY_DEFAULT_PITCH.equals(preference.getKey())) {
|
updateLanguageTo(
|
||||||
updateSpeechPitchValue((Integer) objValue);
|
(!TextUtils.isEmpty(localeString)
|
||||||
|
? mEnginesHelper.parseLocaleString(localeString)
|
||||||
|
: null));
|
||||||
|
checkDefaultLocale();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
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
|
* Ask the current default engine to launch the matching INSTALL_TTS_DATA activity so the
|
||||||
* clicked.
|
* 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
|
@Override
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
@@ -541,57 +606,15 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment implements
|
|||||||
// the actual speaking
|
// the actual speaking
|
||||||
speakSampleText();
|
speakSampleText();
|
||||||
return true;
|
return true;
|
||||||
} else if (preference == mResetSpeechRate) {
|
} else if (preference == mInstallVoicesPreference) {
|
||||||
int speechRateSeekbarProgress = getSeekBarProgressFromValue(
|
installVoiceData();
|
||||||
KEY_DEFAULT_RATE, TextToSpeech.Engine.DEFAULT_RATE);
|
return true;
|
||||||
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;
|
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) {
|
private void updateWidgetState(boolean enable) {
|
||||||
mPlayExample.setEnabled(enable);
|
mPlayExample.setEnabled(enable);
|
||||||
mDefaultRatePref.setEnabled(enable);
|
|
||||||
mEngineStatus.setEnabled(enable);
|
mEngineStatus.setEnabled(enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,67 +637,7 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment implements
|
|||||||
dialog.show();
|
dialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateDefaultEngine(String engine) {
|
/** Check whether the voice data for the engine is ok. */
|
||||||
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.
|
|
||||||
*/
|
|
||||||
private void checkVoiceData(String engine) {
|
private void checkVoiceData(String engine) {
|
||||||
Intent intent = new Intent(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
|
Intent intent = new Intent(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
|
||||||
intent.setPackage(engine);
|
intent.setPackage(engine);
|
||||||
@@ -686,9 +649,7 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/** The voice data check is complete. */
|
||||||
* Step 5: The voice data check is complete.
|
|
||||||
*/
|
|
||||||
private void onVoiceDataIntegrityCheckDone(Intent data) {
|
private void onVoiceDataIntegrityCheckDone(Intent data) {
|
||||||
final String engine = mTts.getCurrentEngine();
|
final String engine = mTts.getCurrentEngine();
|
||||||
|
|
||||||
@@ -715,39 +676,5 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment implements
|
|||||||
if (evaluateDefaultLocale()) {
|
if (evaluateDefaultLocale()) {
|
||||||
getSampleText();
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -20,50 +20,22 @@ import android.app.AlertDialog;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
|
||||||
import android.speech.tts.TextToSpeech.EngineInfo;
|
import android.speech.tts.TextToSpeech.EngineInfo;
|
||||||
import android.support.v7.preference.Preference;
|
import android.support.v7.preference.Preference;
|
||||||
import android.support.v7.preference.PreferenceViewHolder;
|
import android.support.v7.preference.PreferenceViewHolder;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
|
||||||
import android.widget.Checkable;
|
import android.widget.Checkable;
|
||||||
import android.widget.CompoundButton;
|
import android.widget.CompoundButton;
|
||||||
import android.widget.RadioButton;
|
import android.widget.RadioButton;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.SettingsActivity;
|
import com.android.settings.SettingsActivity;
|
||||||
import com.android.settings.Utils;
|
|
||||||
|
|
||||||
|
|
||||||
public class TtsEnginePreference extends Preference {
|
public class TtsEnginePreference extends Preference {
|
||||||
|
|
||||||
private static final String TAG = "TtsEnginePreference";
|
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.
|
* The engine information for the engine this preference represents.
|
||||||
* Contains it's name, label etc. which are used for display.
|
* Contains it's name, label etc. which are used for display.
|
||||||
@@ -81,7 +53,6 @@ public class TtsEnginePreference extends Preference {
|
|||||||
*/
|
*/
|
||||||
private volatile boolean mPreventRadioButtonCallbacks;
|
private volatile boolean mPreventRadioButtonCallbacks;
|
||||||
|
|
||||||
private View mSettingsIcon;
|
|
||||||
private RadioButton mRadioButton;
|
private RadioButton mRadioButton;
|
||||||
private Intent mVoiceCheckData;
|
private Intent mVoiceCheckData;
|
||||||
|
|
||||||
@@ -99,7 +70,6 @@ public class TtsEnginePreference extends Preference {
|
|||||||
setLayoutResource(R.layout.preference_tts_engine);
|
setLayoutResource(R.layout.preference_tts_engine);
|
||||||
|
|
||||||
mSharedState = state;
|
mSharedState = state;
|
||||||
mSettingsActivity = prefActivity;
|
|
||||||
mEngineInfo = info;
|
mEngineInfo = info;
|
||||||
mPreventRadioButtonCallbacks = false;
|
mPreventRadioButtonCallbacks = false;
|
||||||
|
|
||||||
@@ -130,52 +100,10 @@ public class TtsEnginePreference extends Preference {
|
|||||||
mPreventRadioButtonCallbacks = false;
|
mPreventRadioButtonCallbacks = false;
|
||||||
|
|
||||||
mRadioButton = rb;
|
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) {
|
public void setVoiceDataDetails(Intent data) {
|
||||||
mVoiceCheckData = 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() {
|
private boolean shouldDisplayDataAlert() {
|
||||||
@@ -227,8 +155,6 @@ public class TtsEnginePreference extends Preference {
|
|||||||
// Privileged engine, set it current
|
// Privileged engine, set it current
|
||||||
makeCurrentEngine(buttonView);
|
makeCurrentEngine(buttonView);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
mSettingsIcon.setEnabled(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,7 +165,6 @@ public class TtsEnginePreference extends Preference {
|
|||||||
mSharedState.setCurrentChecked(current);
|
mSharedState.setCurrentChecked(current);
|
||||||
mSharedState.setCurrentKey(getKey());
|
mSharedState.setCurrentKey(getKey());
|
||||||
callChangeListener(mSharedState.getCurrentKey());
|
callChangeListener(mSharedState.getCurrentKey());
|
||||||
mSettingsIcon.setEnabled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
194
src/com/android/settings/tts/TtsEnginePreferenceFragment.java
Normal file
194
src/com/android/settings/tts/TtsEnginePreferenceFragment.java
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
207
src/com/android/settings/tts/TtsSlidersFragment.java
Normal file
207
src/com/android/settings/tts/TtsSlidersFragment.java
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
Reference in New Issue
Block a user