Merge "Remove the "deprecated" classes"
commit
338ba2a236
|
@ -403,12 +403,6 @@
|
||||||
<attr name="parentStyle" format="string" />
|
<attr name="parentStyle" format="string" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
<!-- TODO: Should be removed. This is no longer required if InputMethodSubtype is supported. -->
|
|
||||||
<declare-styleable name="KeyboardSet">
|
|
||||||
<!-- Locale of the keyboard layouts -->
|
|
||||||
<attr name="keyboardLocale" format="string" />
|
|
||||||
</declare-styleable>
|
|
||||||
|
|
||||||
<declare-styleable name="KeyboardSet_Element">
|
<declare-styleable name="KeyboardSet_Element">
|
||||||
<!-- This should be aligned with KeyboardId.ELEMENT_* -->
|
<!-- This should be aligned with KeyboardId.ELEMENT_* -->
|
||||||
<attr name="elementName" format="enum">
|
<attr name="elementName" format="enum">
|
||||||
|
|
|
@ -207,75 +207,6 @@
|
||||||
<!-- Spoken feedback after changing to the shifted phone dialer (symbols) keyboard. -->
|
<!-- Spoken feedback after changing to the shifted phone dialer (symbols) keyboard. -->
|
||||||
<string name="spoken_description_mode_phone_shift">Phone symbols mode</string>
|
<string name="spoken_description_mode_phone_shift">Phone symbols mode</string>
|
||||||
|
|
||||||
<!-- Voice related labels -->
|
|
||||||
|
|
||||||
<!-- Title of the warning dialog that shows when a user initiates voice input for
|
|
||||||
the first time. -->
|
|
||||||
<string name="voice_warning_title">Voice input</string>
|
|
||||||
|
|
||||||
<!-- Message that gets put at the top of the warning dialog if the user is attempting to use
|
|
||||||
voice input in a currently unsupported locale. Voice input will work for such a user,
|
|
||||||
but it will only recognize them in English. -->
|
|
||||||
<string name="voice_warning_locale_not_supported">Voice input is not currently supported for your language, but does work in English.</string>
|
|
||||||
|
|
||||||
<!-- Message of the warning dialog that shows when a user initiates voice input for
|
|
||||||
the first time, or turns it on in settings. [CHAR LIMIT=200] -->
|
|
||||||
<string name="voice_warning_may_not_understand">Voice input uses Google\'s speech recognition. <a href="http://m.google.com/privacy">The Mobile Privacy Policy</a> applies.</string>
|
|
||||||
|
|
||||||
<!-- An additional part of the warning dialog for voice input that only shows when the user
|
|
||||||
actually initiates voice input, rather than just turning it on in settings. [CHAR LIMIT=200] -->
|
|
||||||
<string name="voice_warning_how_to_turn_off">To turn off voice input, go to input method settings.</string>
|
|
||||||
|
|
||||||
<!-- Message to show when user enables the voice input settings (which says
|
|
||||||
"Press the microphone button"). [CHAR LIMIT=100] -->
|
|
||||||
<string name="voice_hint_dialog_message">To use voice input, press the microphone button.</string>
|
|
||||||
|
|
||||||
<!-- Short message to tell the user the system is ready for them to speak. -->
|
|
||||||
<string name="voice_listening">Speak now</string>
|
|
||||||
|
|
||||||
<!-- Short message shown after the user finishes speaking. -->
|
|
||||||
<string name="voice_working">Working</string>
|
|
||||||
|
|
||||||
<!-- Short message shown before the user should speak. -->
|
|
||||||
<string name="voice_initializing"></string>
|
|
||||||
|
|
||||||
<!-- Short message shown when a generic error occurs. -->
|
|
||||||
<string name="voice_error">Error. Please try again.</string>
|
|
||||||
|
|
||||||
<!-- Short message shown for a network error. -->
|
|
||||||
<string name="voice_network_error">Couldn\'t connect</string>
|
|
||||||
|
|
||||||
<!-- Short message shown for a network error where the utterance was really long,
|
|
||||||
in which case we should suggest that the user speak less. -->
|
|
||||||
<string name="voice_too_much_speech">Error, too much speech.</string>
|
|
||||||
|
|
||||||
<!-- Short message shown for an audio error. -->
|
|
||||||
<string name="voice_audio_error">Audio problem</string>
|
|
||||||
|
|
||||||
<!-- Short message shown for an error with the voice server. -->
|
|
||||||
<string name="voice_server_error">Server error</string>
|
|
||||||
|
|
||||||
<!-- Short message shown when no speech is heard. -->
|
|
||||||
<string name="voice_speech_timeout">No speech heard</string>
|
|
||||||
|
|
||||||
<!-- Short message shown when the server couldn't parse any speech. -->
|
|
||||||
<string name="voice_no_match">No matches found</string>
|
|
||||||
|
|
||||||
<!-- Short message shown when the user initiates voice and voice search is not installed. -->
|
|
||||||
<string name="voice_not_installed">Voice search not installed</string>
|
|
||||||
|
|
||||||
<!-- Short hint shown in candidate view to explain voice input. -->
|
|
||||||
<string name="voice_swipe_hint"><b>Hint:</b> Swipe across keyboard to speak</string>
|
|
||||||
|
|
||||||
<!-- Short hint shown in candidate view to explain that user can speak punctuation. -->
|
|
||||||
<string name="voice_punctuation_hint"><b>Hint:</b> Next time, try speaking punctuation like \"period\", \"comma\", or \"question mark\".</string>
|
|
||||||
|
|
||||||
<!-- Label on button to stop recognition. Must be short to fit on button. -->
|
|
||||||
<string name="cancel">Cancel</string>
|
|
||||||
|
|
||||||
<!-- Label on button when an error occurs -->
|
|
||||||
<string name="ok">OK</string>
|
|
||||||
|
|
||||||
<!-- Preferences item for enabling speech input -->
|
<!-- Preferences item for enabling speech input -->
|
||||||
<string name="voice_input">Voice input key</string>
|
<string name="voice_input">Voice input key</string>
|
||||||
|
|
||||||
|
@ -294,9 +225,6 @@
|
||||||
<!-- On settings screen, voice input pop-up menu summary text to never show voice key [CHAR LIMIT=20] -->
|
<!-- On settings screen, voice input pop-up menu summary text to never show voice key [CHAR LIMIT=20] -->
|
||||||
<string name="voice_input_modes_summary_off">Voice input is disabled</string>
|
<string name="voice_input_modes_summary_off">Voice input is disabled</string>
|
||||||
|
|
||||||
<!-- Title of the dialog for selecting input methods. [CHAR LIMIT=20] -->
|
|
||||||
<string name="selectInputMethod">Select input method</string>
|
|
||||||
|
|
||||||
<!-- Title for configuring input method settings [CHAR LIMIT=35] -->
|
<!-- Title for configuring input method settings [CHAR LIMIT=35] -->
|
||||||
<string name="configure_input_method">Configure input methods</string>
|
<string name="configure_input_method">Configure input methods</string>
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="ar" >
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_arabic"
|
latin:elementKeyboard="@xml/kbd_arabic"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="be">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_east_slavic"
|
latin:elementKeyboard="@xml/kbd_east_slavic"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="bg">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_bulgarian"
|
latin:elementKeyboard="@xml/kbd_bulgarian"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="cs">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_qwertz"
|
latin:elementKeyboard="@xml/kbd_qwertz"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="da">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_nordic"
|
latin:elementKeyboard="@xml/kbd_nordic"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="de">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_qwerty"
|
latin:elementKeyboard="@xml/kbd_qwerty"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="de">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_qwertz"
|
latin:elementKeyboard="@xml/kbd_qwertz"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="el">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_greek"
|
latin:elementKeyboard="@xml/kbd_greek"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="es,es_US">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_spanish"
|
latin:elementKeyboard="@xml/kbd_spanish"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="et">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_nordic"
|
latin:elementKeyboard="@xml/kbd_nordic"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="fa" >
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_farsi"
|
latin:elementKeyboard="@xml/kbd_farsi"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="fi">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_nordic"
|
latin:elementKeyboard="@xml/kbd_nordic"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="fr_CA">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_qwerty"
|
latin:elementKeyboard="@xml/kbd_qwerty"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="fr_CH">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_qwertz"
|
latin:elementKeyboard="@xml/kbd_qwertz"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="fr">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_azerty"
|
latin:elementKeyboard="@xml/kbd_azerty"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="hi">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_hindi"
|
latin:elementKeyboard="@xml/kbd_hindi"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="hr">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_qwertz"
|
latin:elementKeyboard="@xml/kbd_qwertz"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="hu">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_qwertz"
|
latin:elementKeyboard="@xml/kbd_qwertz"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="is">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_nordic"
|
latin:elementKeyboard="@xml/kbd_nordic"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="iw">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_hebrew"
|
latin:elementKeyboard="@xml/kbd_hebrew"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="ka">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_georgian"
|
latin:elementKeyboard="@xml/kbd_georgian"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="ky">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_east_slavic"
|
latin:elementKeyboard="@xml/kbd_east_slavic"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="mk">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_south_slavic"
|
latin:elementKeyboard="@xml/kbd_south_slavic"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="nb">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_nordic"
|
latin:elementKeyboard="@xml/kbd_nordic"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="pl">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_qwerty"
|
latin:elementKeyboard="@xml/kbd_qwerty"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="pt">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_qwerty"
|
latin:elementKeyboard="@xml/kbd_qwerty"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="ro">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_qwerty"
|
latin:elementKeyboard="@xml/kbd_qwerty"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="ru">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_east_slavic"
|
latin:elementKeyboard="@xml/kbd_east_slavic"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="sk">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_qwerty"
|
latin:elementKeyboard="@xml/kbd_qwerty"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="sl">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_qwerty"
|
latin:elementKeyboard="@xml/kbd_qwerty"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="sr">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_south_slavic"
|
latin:elementKeyboard="@xml/kbd_south_slavic"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="sv">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_nordic"
|
latin:elementKeyboard="@xml/kbd_nordic"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="th">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_thai"
|
latin:elementKeyboard="@xml/kbd_thai"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="tr">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_qwerty"
|
latin:elementKeyboard="@xml/kbd_qwerty"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="uk">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_east_slavic"
|
latin:elementKeyboard="@xml/kbd_east_slavic"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="vi">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_qwerty"
|
latin:elementKeyboard="@xml/kbd_qwerty"
|
||||||
|
|
|
@ -19,8 +19,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<KeyboardSet
|
<KeyboardSet
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
|
||||||
latin:keyboardLocale="en_GB,en_US">
|
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_qwerty"
|
latin:elementKeyboard="@xml/kbd_qwerty"
|
||||||
|
|
|
@ -29,7 +29,6 @@ import android.util.Log;
|
||||||
import android.view.inputmethod.InputMethodInfo;
|
import android.view.inputmethod.InputMethodInfo;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
|
||||||
import com.android.inputmethod.deprecated.LanguageSwitcherProxy;
|
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
import com.android.inputmethod.latin.SubtypeSwitcher;
|
import com.android.inputmethod.latin.SubtypeSwitcher;
|
||||||
import com.android.inputmethod.latin.SubtypeUtils;
|
import com.android.inputmethod.latin.SubtypeUtils;
|
||||||
|
@ -68,14 +67,6 @@ public class InputMethodManagerCompatWrapper {
|
||||||
private static final InputMethodManagerCompatWrapper sInstance =
|
private static final InputMethodManagerCompatWrapper sInstance =
|
||||||
new InputMethodManagerCompatWrapper();
|
new InputMethodManagerCompatWrapper();
|
||||||
|
|
||||||
public static final boolean SUBTYPE_SUPPORTED;
|
|
||||||
|
|
||||||
static {
|
|
||||||
// This static initializer guarantees that METHOD_getShortcutInputMethodsAndSubtypes is
|
|
||||||
// already instantiated.
|
|
||||||
SUBTYPE_SUPPORTED = METHOD_getShortcutInputMethodsAndSubtypes != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For the compatibility, IMM will create dummy subtypes if subtypes are not found.
|
// For the compatibility, IMM will create dummy subtypes if subtypes are not found.
|
||||||
// This is required to be false if the current behavior is broken. For now, it's ok to be true.
|
// This is required to be false if the current behavior is broken. For now, it's ok to be true.
|
||||||
public static final boolean FORCE_ENABLE_VOICE_EVEN_WITH_NO_VOICE_SUBTYPES =
|
public static final boolean FORCE_ENABLE_VOICE_EVEN_WITH_NO_VOICE_SUBTYPES =
|
||||||
|
@ -87,7 +78,6 @@ public class InputMethodManagerCompatWrapper {
|
||||||
private InputMethodManager mImm;
|
private InputMethodManager mImm;
|
||||||
private PackageManager mPackageManager;
|
private PackageManager mPackageManager;
|
||||||
private ApplicationInfo mApplicationInfo;
|
private ApplicationInfo mApplicationInfo;
|
||||||
private LanguageSwitcherProxy mLanguageSwitcherProxy;
|
|
||||||
private String mLatinImePackageName;
|
private String mLatinImePackageName;
|
||||||
|
|
||||||
public static InputMethodManagerCompatWrapper getInstance() {
|
public static InputMethodManagerCompatWrapper getInstance() {
|
||||||
|
@ -103,39 +93,20 @@ public class InputMethodManagerCompatWrapper {
|
||||||
sInstance.mLatinImePackageName = service.getPackageName();
|
sInstance.mLatinImePackageName = service.getPackageName();
|
||||||
sInstance.mPackageManager = service.getPackageManager();
|
sInstance.mPackageManager = service.getPackageManager();
|
||||||
sInstance.mApplicationInfo = service.getApplicationInfo();
|
sInstance.mApplicationInfo = service.getApplicationInfo();
|
||||||
sInstance.mLanguageSwitcherProxy = LanguageSwitcherProxy.getInstance();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputMethodSubtypeCompatWrapper getCurrentInputMethodSubtype() {
|
public InputMethodSubtypeCompatWrapper getCurrentInputMethodSubtype() {
|
||||||
if (!SUBTYPE_SUPPORTED) {
|
|
||||||
return new InputMethodSubtypeCompatWrapper(
|
|
||||||
0, 0, mLanguageSwitcherProxy.getInputLocale().toString(), KEYBOARD_MODE, "");
|
|
||||||
}
|
|
||||||
Object o = CompatUtils.invoke(mImm, null, METHOD_getCurrentInputMethodSubtype);
|
Object o = CompatUtils.invoke(mImm, null, METHOD_getCurrentInputMethodSubtype);
|
||||||
return new InputMethodSubtypeCompatWrapper(o);
|
return new InputMethodSubtypeCompatWrapper(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputMethodSubtypeCompatWrapper getLastInputMethodSubtype() {
|
public InputMethodSubtypeCompatWrapper getLastInputMethodSubtype() {
|
||||||
if (!SUBTYPE_SUPPORTED) {
|
|
||||||
return new InputMethodSubtypeCompatWrapper(
|
|
||||||
0, 0, mLanguageSwitcherProxy.getInputLocale().toString(), KEYBOARD_MODE, "");
|
|
||||||
}
|
|
||||||
Object o = CompatUtils.invoke(mImm, null, METHOD_getLastInputMethodSubtype);
|
Object o = CompatUtils.invoke(mImm, null, METHOD_getLastInputMethodSubtype);
|
||||||
return new InputMethodSubtypeCompatWrapper(o);
|
return new InputMethodSubtypeCompatWrapper(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<InputMethodSubtypeCompatWrapper> getEnabledInputMethodSubtypeList(
|
public List<InputMethodSubtypeCompatWrapper> getEnabledInputMethodSubtypeList(
|
||||||
InputMethodInfoCompatWrapper imi, boolean allowsImplicitlySelectedSubtypes) {
|
InputMethodInfoCompatWrapper imi, boolean allowsImplicitlySelectedSubtypes) {
|
||||||
if (!SUBTYPE_SUPPORTED) {
|
|
||||||
String[] languages = mLanguageSwitcherProxy.getEnabledLanguages(
|
|
||||||
allowsImplicitlySelectedSubtypes);
|
|
||||||
List<InputMethodSubtypeCompatWrapper> subtypeList =
|
|
||||||
new ArrayList<InputMethodSubtypeCompatWrapper>();
|
|
||||||
for (String lang: languages) {
|
|
||||||
subtypeList.add(new InputMethodSubtypeCompatWrapper(0, 0, lang, KEYBOARD_MODE, ""));
|
|
||||||
}
|
|
||||||
return subtypeList;
|
|
||||||
}
|
|
||||||
Object retval = CompatUtils.invoke(mImm, null, METHOD_getEnabledInputMethodSubtypeList,
|
Object retval = CompatUtils.invoke(mImm, null, METHOD_getEnabledInputMethodSubtypeList,
|
||||||
(imi != null ? imi.getInputMethodInfo() : null), allowsImplicitlySelectedSubtypes);
|
(imi != null ? imi.getInputMethodInfo() : null), allowsImplicitlySelectedSubtypes);
|
||||||
if (retval == null || !(retval instanceof List<?>) || ((List<?>)retval).isEmpty()) {
|
if (retval == null || !(retval instanceof List<?>) || ((List<?>)retval).isEmpty()) {
|
||||||
|
@ -228,16 +199,10 @@ public class InputMethodManagerCompatWrapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean switchToLastInputMethod(IBinder token) {
|
public boolean switchToLastInputMethod(IBinder token) {
|
||||||
if (SubtypeSwitcher.getInstance().isDummyVoiceMode()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return (Boolean)CompatUtils.invoke(mImm, false, METHOD_switchToLastInputMethod, token);
|
return (Boolean)CompatUtils.invoke(mImm, false, METHOD_switchToLastInputMethod, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean switchToNextInputMethod(IBinder token, boolean onlyCurrentIme) {
|
public boolean switchToNextInputMethod(IBinder token, boolean onlyCurrentIme) {
|
||||||
if (SubtypeSwitcher.getInstance().isDummyVoiceMode()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return (Boolean)CompatUtils.invoke(mImm, false, METHOD_switchToNextInputMethod, token,
|
return (Boolean)CompatUtils.invoke(mImm, false, METHOD_switchToNextInputMethod, token,
|
||||||
onlyCurrentIme);
|
onlyCurrentIme);
|
||||||
}
|
}
|
||||||
|
@ -253,88 +218,6 @@ public class InputMethodManagerCompatWrapper {
|
||||||
|
|
||||||
public void showInputMethodPicker() {
|
public void showInputMethodPicker() {
|
||||||
if (mImm == null) return;
|
if (mImm == null) return;
|
||||||
if (SUBTYPE_SUPPORTED) {
|
mImm.showInputMethodPicker();
|
||||||
mImm.showInputMethodPicker();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The code below are based on {@link InputMethodManager#showInputMethodMenuInternal}.
|
|
||||||
|
|
||||||
final InputMethodInfoCompatWrapper myImi = SubtypeUtils.getInputMethodInfo(
|
|
||||||
mLatinImePackageName);
|
|
||||||
final List<InputMethodSubtypeCompatWrapper> myImsList = getEnabledInputMethodSubtypeList(
|
|
||||||
myImi, true);
|
|
||||||
final InputMethodSubtypeCompatWrapper currentIms = getCurrentInputMethodSubtype();
|
|
||||||
final List<InputMethodInfoCompatWrapper> imiList = getEnabledInputMethodList();
|
|
||||||
imiList.remove(myImi);
|
|
||||||
final PackageManager pm = mPackageManager;
|
|
||||||
Collections.sort(imiList, new Comparator<InputMethodInfoCompatWrapper>() {
|
|
||||||
@Override
|
|
||||||
public int compare(InputMethodInfoCompatWrapper imi1,
|
|
||||||
InputMethodInfoCompatWrapper imi2) {
|
|
||||||
final CharSequence imiId1 = imi1.loadLabel(pm) + "/" + imi1.getId();
|
|
||||||
final CharSequence imiId2 = imi2.loadLabel(pm) + "/" + imi2.getId();
|
|
||||||
return imiId1.toString().compareTo(imiId2.toString());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
final int myImsCount = myImsList.size();
|
|
||||||
final int imiCount = imiList.size();
|
|
||||||
final CharSequence[] items = new CharSequence[myImsCount + imiCount];
|
|
||||||
|
|
||||||
int checkedItem = 0;
|
|
||||||
int index = 0;
|
|
||||||
final CharSequence myImiLabel = myImi.loadLabel(mPackageManager);
|
|
||||||
for (int i = 0; i < myImsCount; i++) {
|
|
||||||
InputMethodSubtypeCompatWrapper ims = myImsList.get(i);
|
|
||||||
if (currentIms.equals(ims))
|
|
||||||
checkedItem = index;
|
|
||||||
final CharSequence title = TextUtils.concat(
|
|
||||||
ims.getDisplayName(mService, mLatinImePackageName, mApplicationInfo),
|
|
||||||
" (" + myImiLabel, ")");
|
|
||||||
items[index] = title;
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < imiCount; i++) {
|
|
||||||
final InputMethodInfoCompatWrapper imi = imiList.get(i);
|
|
||||||
final CharSequence title = imi.loadLabel(mPackageManager);
|
|
||||||
items[index] = title;
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
final InputMethodServiceCompatWrapper service = mService;
|
|
||||||
final OnClickListener buttonListener = new OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface di, int whichButton) {
|
|
||||||
final Intent intent = new Intent("android.settings.INPUT_METHOD_SETTINGS");
|
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
|
||||||
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
|
|
||||||
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
||||||
service.startActivity(intent);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
final IBinder token = service.getWindow().getWindow().getAttributes().token;
|
|
||||||
final OnClickListener selectionListener = new OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface di, int which) {
|
|
||||||
di.dismiss();
|
|
||||||
if (which < myImsCount) {
|
|
||||||
final int imsIndex = which;
|
|
||||||
final InputMethodSubtypeCompatWrapper ims = myImsList.get(imsIndex);
|
|
||||||
service.notifyOnCurrentInputMethodSubtypeChanged(ims);
|
|
||||||
} else {
|
|
||||||
final int imiIndex = which - myImsCount;
|
|
||||||
final InputMethodInfoCompatWrapper imi = imiList.get(imiIndex);
|
|
||||||
setInputMethodAndSubtype(token, imi.getId(), null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
final AlertDialog.Builder builder = new AlertDialog.Builder(mService)
|
|
||||||
.setTitle(mService.getString(R.string.selectInputMethod))
|
|
||||||
.setNeutralButton(R.string.configure_input_method, buttonListener)
|
|
||||||
.setSingleChoiceItems(items, checkedItem, selectionListener);
|
|
||||||
mService.showOptionDialogInternal(builder.create());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ import android.view.Window;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.view.inputmethod.InputMethodSubtype;
|
import android.view.inputmethod.InputMethodSubtype;
|
||||||
|
|
||||||
import com.android.inputmethod.deprecated.LanguageSwitcherProxy;
|
|
||||||
import com.android.inputmethod.keyboard.KeyboardSwitcher;
|
import com.android.inputmethod.keyboard.KeyboardSwitcher;
|
||||||
import com.android.inputmethod.latin.SubtypeSwitcher;
|
import com.android.inputmethod.latin.SubtypeSwitcher;
|
||||||
|
|
||||||
|
@ -87,9 +86,6 @@ public class InputMethodServiceCompatWrapper extends InputMethodService {
|
||||||
if (subtype != null) {
|
if (subtype != null) {
|
||||||
if (!InputMethodManagerCompatWrapper.FORCE_ENABLE_VOICE_EVEN_WITH_NO_VOICE_SUBTYPES
|
if (!InputMethodManagerCompatWrapper.FORCE_ENABLE_VOICE_EVEN_WITH_NO_VOICE_SUBTYPES
|
||||||
&& !subtype.isDummy()) return;
|
&& !subtype.isDummy()) return;
|
||||||
if (!InputMethodManagerCompatWrapper.SUBTYPE_SUPPORTED) {
|
|
||||||
LanguageSwitcherProxy.getInstance().setLocale(subtype.getLocale());
|
|
||||||
}
|
|
||||||
SubtypeSwitcher.getInstance().updateSubtype(subtype);
|
SubtypeSwitcher.getInstance().updateSubtype(subtype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,90 +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.inputmethod.deprecated;
|
|
||||||
|
|
||||||
import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
|
|
||||||
import com.android.inputmethod.deprecated.languageswitcher.LanguageSwitcher;
|
|
||||||
import com.android.inputmethod.latin.LatinIME;
|
|
||||||
import com.android.inputmethod.latin.Settings;
|
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.res.Configuration;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
// This class is used only when the IME doesn't use method.xml for language switching.
|
|
||||||
public class LanguageSwitcherProxy implements SharedPreferences.OnSharedPreferenceChangeListener {
|
|
||||||
private static final LanguageSwitcherProxy sInstance = new LanguageSwitcherProxy();
|
|
||||||
private LatinIME mService;
|
|
||||||
private LanguageSwitcher mLanguageSwitcher;
|
|
||||||
private SharedPreferences mPrefs;
|
|
||||||
|
|
||||||
public static LanguageSwitcherProxy getInstance() {
|
|
||||||
if (InputMethodManagerCompatWrapper.SUBTYPE_SUPPORTED) return null;
|
|
||||||
return sInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void init(LatinIME service, SharedPreferences prefs) {
|
|
||||||
if (InputMethodManagerCompatWrapper.SUBTYPE_SUPPORTED) return;
|
|
||||||
final Configuration conf = service.getResources().getConfiguration();
|
|
||||||
sInstance.mLanguageSwitcher = new LanguageSwitcher(service);
|
|
||||||
sInstance.mLanguageSwitcher.loadLocales(prefs, conf.locale);
|
|
||||||
sInstance.mPrefs = prefs;
|
|
||||||
sInstance.mService = service;
|
|
||||||
prefs.registerOnSharedPreferenceChangeListener(sInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void onConfigurationChanged(Configuration conf) {
|
|
||||||
if (InputMethodManagerCompatWrapper.SUBTYPE_SUPPORTED) return;
|
|
||||||
sInstance.mLanguageSwitcher.onConfigurationChanged(conf, sInstance.mPrefs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void loadSettings() {
|
|
||||||
if (InputMethodManagerCompatWrapper.SUBTYPE_SUPPORTED) return;
|
|
||||||
sInstance.mLanguageSwitcher.loadLocales(sInstance.mPrefs, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLocaleCount() {
|
|
||||||
return mLanguageSwitcher.getLocaleCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getEnabledLanguages(boolean allowImplicitlySelectedLanguages) {
|
|
||||||
return mLanguageSwitcher.getEnabledLanguages(allowImplicitlySelectedLanguages);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Locale getInputLocale() {
|
|
||||||
return mLanguageSwitcher.getInputLocale();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLocale(String localeStr) {
|
|
||||||
mLanguageSwitcher.setLocale(localeStr);
|
|
||||||
mLanguageSwitcher.persist(mPrefs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
|
|
||||||
// PREF_SELECTED_LANGUAGES: enabled input subtypes
|
|
||||||
// PREF_INPUT_LANGUAGE: current input subtype
|
|
||||||
if (key.equals(Settings.PREF_SELECTED_LANGUAGES)
|
|
||||||
|| key.equals(Settings.PREF_INPUT_LANGUAGE)) {
|
|
||||||
mLanguageSwitcher.loadLocales(prefs, null);
|
|
||||||
if (mService != null) {
|
|
||||||
mService.onRefreshKeyboard();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,854 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2010 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.inputmethod.deprecated;
|
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.IBinder;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.provider.Browser;
|
|
||||||
import android.speech.SpeechRecognizer;
|
|
||||||
import android.text.SpannableStringBuilder;
|
|
||||||
import android.text.Spanned;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.text.method.LinkMovementMethod;
|
|
||||||
import android.text.style.URLSpan;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.ViewParent;
|
|
||||||
import android.view.Window;
|
|
||||||
import android.view.WindowManager;
|
|
||||||
import android.view.inputmethod.EditorInfo;
|
|
||||||
import android.view.inputmethod.ExtractedTextRequest;
|
|
||||||
import android.view.inputmethod.InputConnection;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
|
|
||||||
import com.android.inputmethod.compat.InputMethodServiceCompatWrapper;
|
|
||||||
import com.android.inputmethod.compat.SharedPreferencesCompat;
|
|
||||||
import com.android.inputmethod.deprecated.voice.FieldContext;
|
|
||||||
import com.android.inputmethod.deprecated.voice.Hints;
|
|
||||||
import com.android.inputmethod.deprecated.voice.SettingsUtil;
|
|
||||||
import com.android.inputmethod.deprecated.voice.VoiceInput;
|
|
||||||
import com.android.inputmethod.keyboard.KeyboardSwitcher;
|
|
||||||
import com.android.inputmethod.keyboard.LatinKeyboardView;
|
|
||||||
import com.android.inputmethod.latin.EditingUtils;
|
|
||||||
import com.android.inputmethod.latin.LastComposedWord;
|
|
||||||
import com.android.inputmethod.latin.LatinIME;
|
|
||||||
import com.android.inputmethod.latin.LatinIME.UIHandler;
|
|
||||||
import com.android.inputmethod.latin.LatinImeLogger;
|
|
||||||
import com.android.inputmethod.latin.R;
|
|
||||||
import com.android.inputmethod.latin.StringUtils;
|
|
||||||
import com.android.inputmethod.latin.SubtypeSwitcher;
|
|
||||||
import com.android.inputmethod.latin.Utils;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class VoiceProxy implements VoiceInput.UiListener {
|
|
||||||
private static final VoiceProxy sInstance = new VoiceProxy();
|
|
||||||
|
|
||||||
public static final boolean VOICE_INSTALLED =
|
|
||||||
!InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED;
|
|
||||||
private static final boolean ENABLE_VOICE_BUTTON = true;
|
|
||||||
private static final String PREF_VOICE_MODE = "voice_mode";
|
|
||||||
// Whether or not the user has used voice input before (and thus, whether to show the
|
|
||||||
// first-run warning dialog or not).
|
|
||||||
private static final String PREF_HAS_USED_VOICE_INPUT = "has_used_voice_input";
|
|
||||||
// Whether or not the user has used voice input from an unsupported locale UI before.
|
|
||||||
// For example, the user has a Chinese UI but activates voice input.
|
|
||||||
private static final String PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE =
|
|
||||||
"has_used_voice_input_unsupported_locale";
|
|
||||||
private static final int RECOGNITIONVIEW_HEIGHT_THRESHOLD_RATIO = 6;
|
|
||||||
// TODO: Adjusted on phones for now
|
|
||||||
private static final int RECOGNITIONVIEW_MINIMUM_HEIGHT_DIP = 244;
|
|
||||||
|
|
||||||
private static final String TAG = VoiceProxy.class.getSimpleName();
|
|
||||||
private static final boolean DEBUG = LatinImeLogger.sDBG;
|
|
||||||
|
|
||||||
private boolean mAfterVoiceInput;
|
|
||||||
private boolean mConfigurationChanging;
|
|
||||||
private boolean mHasUsedVoiceInput;
|
|
||||||
private boolean mHasUsedVoiceInputUnsupportedLocale;
|
|
||||||
private boolean mImmediatelyAfterVoiceInput;
|
|
||||||
private boolean mIsShowingHint;
|
|
||||||
private boolean mLocaleSupportedForVoiceInput;
|
|
||||||
private boolean mPasswordText;
|
|
||||||
private boolean mRecognizing;
|
|
||||||
private boolean mShowingVoiceSuggestions;
|
|
||||||
private boolean mVoiceButtonEnabled;
|
|
||||||
private boolean mVoiceButtonOnPrimary;
|
|
||||||
private boolean mVoiceInputHighlighted;
|
|
||||||
|
|
||||||
private int mMinimumVoiceRecognitionViewHeightPixel;
|
|
||||||
private InputMethodManagerCompatWrapper mImm;
|
|
||||||
private LatinIME mService;
|
|
||||||
private AlertDialog mVoiceWarningDialog;
|
|
||||||
private VoiceInput mVoiceInput;
|
|
||||||
private final VoiceResults mVoiceResults = new VoiceResults();
|
|
||||||
private Hints mHints;
|
|
||||||
private UIHandler mHandler;
|
|
||||||
private SubtypeSwitcher mSubtypeSwitcher;
|
|
||||||
|
|
||||||
// For each word, a list of potential replacements, usually from voice.
|
|
||||||
private final Map<String, List<CharSequence>> mWordToSuggestions =
|
|
||||||
new HashMap<String, List<CharSequence>>();
|
|
||||||
|
|
||||||
public static VoiceProxy init(LatinIME context, SharedPreferences prefs, UIHandler h) {
|
|
||||||
sInstance.initInternal(context, prefs, h);
|
|
||||||
return sInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static VoiceProxy getInstance() {
|
|
||||||
return sInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initInternal(LatinIME service, SharedPreferences prefs, UIHandler h) {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mService = service;
|
|
||||||
mHandler = h;
|
|
||||||
mMinimumVoiceRecognitionViewHeightPixel = Utils.dipToPixel(
|
|
||||||
Utils.getDipScale(service), RECOGNITIONVIEW_MINIMUM_HEIGHT_DIP);
|
|
||||||
mImm = InputMethodManagerCompatWrapper.getInstance();
|
|
||||||
mSubtypeSwitcher = SubtypeSwitcher.getInstance();
|
|
||||||
mVoiceInput = new VoiceInput(service, this);
|
|
||||||
mHints = new Hints(service, prefs, new Hints.Display() {
|
|
||||||
@Override
|
|
||||||
public void showHint(int viewResource) {
|
|
||||||
View view = LayoutInflater.from(mService).inflate(viewResource, null);
|
|
||||||
mIsShowingHint = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private VoiceProxy() {
|
|
||||||
// Intentional empty constructor for singleton.
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resetVoiceStates(boolean isPasswordText) {
|
|
||||||
mAfterVoiceInput = false;
|
|
||||||
mImmediatelyAfterVoiceInput = false;
|
|
||||||
mShowingVoiceSuggestions = false;
|
|
||||||
mVoiceInputHighlighted = false;
|
|
||||||
mPasswordText = isPasswordText;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void flushVoiceInputLogs() {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!mConfigurationChanging) {
|
|
||||||
if (mAfterVoiceInput) {
|
|
||||||
mVoiceInput.flushAllTextModificationCounters();
|
|
||||||
mVoiceInput.logInputEnded();
|
|
||||||
}
|
|
||||||
mVoiceInput.flushLogs();
|
|
||||||
mVoiceInput.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void flushAndLogAllTextModificationCounters(int index, CharSequence suggestion,
|
|
||||||
String wordSeparators) {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mAfterVoiceInput && mShowingVoiceSuggestions) {
|
|
||||||
mVoiceInput.flushAllTextModificationCounters();
|
|
||||||
// send this intent AFTER logging any prior aggregated edits.
|
|
||||||
mVoiceInput.logTextModifiedByChooseSuggestion(suggestion.toString(), index,
|
|
||||||
wordSeparators, mService.getCurrentInputConnection());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showVoiceWarningDialog(final boolean swipe, IBinder token) {
|
|
||||||
if (mVoiceWarningDialog != null && mVoiceWarningDialog.isShowing()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
AlertDialog.Builder builder = new UrlLinkAlertDialogBuilder(mService);
|
|
||||||
builder.setCancelable(true);
|
|
||||||
builder.setIcon(R.drawable.ic_mic_dialog);
|
|
||||||
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int whichButton) {
|
|
||||||
mVoiceInput.logKeyboardWarningDialogOk();
|
|
||||||
reallyStartListening(swipe);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int whichButton) {
|
|
||||||
mVoiceInput.logKeyboardWarningDialogCancel();
|
|
||||||
switchToLastInputMethod();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// When the dialog is dismissed by user's cancellation, switch back to the last input method
|
|
||||||
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
|
||||||
@Override
|
|
||||||
public void onCancel(DialogInterface arg0) {
|
|
||||||
mVoiceInput.logKeyboardWarningDialogCancel();
|
|
||||||
switchToLastInputMethod();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
final CharSequence message;
|
|
||||||
if (mLocaleSupportedForVoiceInput) {
|
|
||||||
message = TextUtils.concat(
|
|
||||||
mService.getText(R.string.voice_warning_may_not_understand), "\n\n",
|
|
||||||
mService.getText(R.string.voice_warning_how_to_turn_off));
|
|
||||||
} else {
|
|
||||||
message = TextUtils.concat(
|
|
||||||
mService.getText(R.string.voice_warning_locale_not_supported), "\n\n",
|
|
||||||
mService.getText(R.string.voice_warning_may_not_understand), "\n\n",
|
|
||||||
mService.getText(R.string.voice_warning_how_to_turn_off));
|
|
||||||
}
|
|
||||||
builder.setMessage(message);
|
|
||||||
builder.setTitle(R.string.voice_warning_title);
|
|
||||||
mVoiceWarningDialog = builder.create();
|
|
||||||
final Window window = mVoiceWarningDialog.getWindow();
|
|
||||||
final WindowManager.LayoutParams lp = window.getAttributes();
|
|
||||||
lp.token = token;
|
|
||||||
lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
|
|
||||||
window.setAttributes(lp);
|
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
|
|
||||||
mVoiceInput.logKeyboardWarningDialogShown();
|
|
||||||
mVoiceWarningDialog.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class UrlLinkAlertDialogBuilder extends AlertDialog.Builder {
|
|
||||||
private AlertDialog mAlertDialog;
|
|
||||||
|
|
||||||
public UrlLinkAlertDialogBuilder(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AlertDialog.Builder setMessage(CharSequence message) {
|
|
||||||
return super.setMessage(replaceURLSpan(message));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Spanned replaceURLSpan(CharSequence message) {
|
|
||||||
// Replace all spans with the custom span
|
|
||||||
final SpannableStringBuilder ssb = new SpannableStringBuilder(message);
|
|
||||||
for (URLSpan span : ssb.getSpans(0, ssb.length(), URLSpan.class)) {
|
|
||||||
int spanStart = ssb.getSpanStart(span);
|
|
||||||
int spanEnd = ssb.getSpanEnd(span);
|
|
||||||
int spanFlags = ssb.getSpanFlags(span);
|
|
||||||
ssb.removeSpan(span);
|
|
||||||
ssb.setSpan(new ClickableSpan(span.getURL()), spanStart, spanEnd, spanFlags);
|
|
||||||
}
|
|
||||||
return ssb;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AlertDialog create() {
|
|
||||||
final AlertDialog dialog = super.create();
|
|
||||||
|
|
||||||
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
|
|
||||||
@Override
|
|
||||||
public void onShow(DialogInterface dialogInterface) {
|
|
||||||
// Make URL in the dialog message click-able.
|
|
||||||
TextView textView = (TextView) mAlertDialog.findViewById(android.R.id.message);
|
|
||||||
if (textView != null) {
|
|
||||||
textView.setMovementMethod(LinkMovementMethod.getInstance());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mAlertDialog = dialog;
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ClickableSpan extends URLSpan {
|
|
||||||
public ClickableSpan(String url) {
|
|
||||||
super(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(View widget) {
|
|
||||||
Uri uri = Uri.parse(getURL());
|
|
||||||
Context context = widget.getContext();
|
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
|
||||||
// Add this flag to start an activity from service
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
|
|
||||||
// Dismiss the warning dialog and go back to the previous IME.
|
|
||||||
// TODO: If we can find a way to bring the new activity to front while keeping
|
|
||||||
// the warning dialog, we don't need to dismiss it here.
|
|
||||||
mAlertDialog.cancel();
|
|
||||||
context.startActivity(intent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showPunctuationHintIfNecessary() {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
InputConnection ic = mService.getCurrentInputConnection();
|
|
||||||
if (!mImmediatelyAfterVoiceInput && mAfterVoiceInput && ic != null) {
|
|
||||||
if (mHints.showPunctuationHintIfNecessary(ic)) {
|
|
||||||
mVoiceInput.logPunctuationHintDisplayed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mImmediatelyAfterVoiceInput = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void hideVoiceWindow() {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!mConfigurationChanging) {
|
|
||||||
if (mAfterVoiceInput)
|
|
||||||
mVoiceInput.logInputEnded();
|
|
||||||
if (mVoiceWarningDialog != null && mVoiceWarningDialog.isShowing()) {
|
|
||||||
mVoiceInput.logKeyboardWarningDialogDismissed();
|
|
||||||
mVoiceWarningDialog.dismiss();
|
|
||||||
mVoiceWarningDialog = null;
|
|
||||||
}
|
|
||||||
if (VOICE_INSTALLED & mRecognizing) {
|
|
||||||
mVoiceInput.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mWordToSuggestions.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCursorAndSelection(int newSelEnd, int newSelStart) {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mAfterVoiceInput) {
|
|
||||||
mVoiceInput.setCursorPos(newSelEnd);
|
|
||||||
mVoiceInput.setSelectionSpan(newSelEnd - newSelStart);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVoiceInputHighlighted(boolean b) {
|
|
||||||
mVoiceInputHighlighted = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setShowingVoiceSuggestions(boolean b) {
|
|
||||||
mShowingVoiceSuggestions = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isVoiceButtonEnabled() {
|
|
||||||
return mVoiceButtonEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isVoiceButtonOnPrimary() {
|
|
||||||
return mVoiceButtonOnPrimary;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isVoiceInputHighlighted() {
|
|
||||||
return mVoiceInputHighlighted;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRecognizing() {
|
|
||||||
return mRecognizing;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean needsToShowWarningDialog() {
|
|
||||||
return !mHasUsedVoiceInput
|
|
||||||
|| (!mLocaleSupportedForVoiceInput && !mHasUsedVoiceInputUnsupportedLocale);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getAndResetIsShowingHint() {
|
|
||||||
boolean ret = mIsShowingHint;
|
|
||||||
mIsShowingHint = false;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void revertVoiceInput() {
|
|
||||||
InputConnection ic = mService.getCurrentInputConnection();
|
|
||||||
if (ic != null) ic.commitText("", 1);
|
|
||||||
mService.updateSuggestions();
|
|
||||||
mVoiceInputHighlighted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void commitVoiceInput() {
|
|
||||||
if (VOICE_INSTALLED && mVoiceInputHighlighted) {
|
|
||||||
InputConnection ic = mService.getCurrentInputConnection();
|
|
||||||
if (ic != null) ic.finishComposingText();
|
|
||||||
mService.updateSuggestions();
|
|
||||||
mVoiceInputHighlighted = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean logAndRevertVoiceInput() {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (mVoiceInputHighlighted) {
|
|
||||||
mVoiceInput.incrementTextModificationDeleteCount(
|
|
||||||
mVoiceResults.candidates.get(0).toString().length());
|
|
||||||
revertVoiceInput();
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void rememberReplacedWord(CharSequence suggestion,String wordSeparators) {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mShowingVoiceSuggestions) {
|
|
||||||
// Retain the replaced word in the alternatives array.
|
|
||||||
String wordToBeReplaced = EditingUtils.getWordAtCursor(
|
|
||||||
mService.getCurrentInputConnection(), wordSeparators);
|
|
||||||
if (!mWordToSuggestions.containsKey(wordToBeReplaced)) {
|
|
||||||
wordToBeReplaced = wordToBeReplaced.toLowerCase();
|
|
||||||
}
|
|
||||||
if (mWordToSuggestions.containsKey(wordToBeReplaced)) {
|
|
||||||
List<CharSequence> suggestions = mWordToSuggestions.get(wordToBeReplaced);
|
|
||||||
if (suggestions.contains(suggestion)) {
|
|
||||||
suggestions.remove(suggestion);
|
|
||||||
}
|
|
||||||
suggestions.add(wordToBeReplaced);
|
|
||||||
mWordToSuggestions.remove(wordToBeReplaced);
|
|
||||||
mWordToSuggestions.put(suggestion.toString(), suggestions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleBackspace() {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mAfterVoiceInput) {
|
|
||||||
// Don't log delete if the user is pressing delete at
|
|
||||||
// the beginning of the text box (hence not deleting anything)
|
|
||||||
if (mVoiceInput.getCursorPos() > 0) {
|
|
||||||
// If anything was selected before the delete was pressed, increment the
|
|
||||||
// delete count by the length of the selection
|
|
||||||
int deleteLen = mVoiceInput.getSelectionSpan() > 0 ?
|
|
||||||
mVoiceInput.getSelectionSpan() : 1;
|
|
||||||
mVoiceInput.incrementTextModificationDeleteCount(deleteLen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleCharacter() {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
commitVoiceInput();
|
|
||||||
if (mAfterVoiceInput) {
|
|
||||||
// Assume input length is 1. This assumption fails for smiley face insertions.
|
|
||||||
mVoiceInput.incrementTextModificationInsertCount(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleSeparator() {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
commitVoiceInput();
|
|
||||||
if (mAfterVoiceInput){
|
|
||||||
// Assume input length is 1. This assumption fails for smiley face insertions.
|
|
||||||
mVoiceInput.incrementTextModificationInsertPunctuationCount(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleClose() {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mRecognizing) {
|
|
||||||
mVoiceInput.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void handleVoiceResults(boolean capitalizeFirstWord) {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mAfterVoiceInput = true;
|
|
||||||
mImmediatelyAfterVoiceInput = true;
|
|
||||||
|
|
||||||
InputConnection ic = mService.getCurrentInputConnection();
|
|
||||||
if (!mService.isFullscreenMode()) {
|
|
||||||
// Start listening for updates to the text from typing, etc.
|
|
||||||
if (ic != null) {
|
|
||||||
ExtractedTextRequest req = new ExtractedTextRequest();
|
|
||||||
ic.getExtractedText(req, InputConnection.GET_EXTRACTED_TEXT_MONITOR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mService.vibrate();
|
|
||||||
|
|
||||||
final List<CharSequence> nBest = new ArrayList<CharSequence>();
|
|
||||||
for (String c : mVoiceResults.candidates) {
|
|
||||||
if (capitalizeFirstWord) {
|
|
||||||
c = Character.toUpperCase(c.charAt(0)) + c.substring(1, c.length());
|
|
||||||
}
|
|
||||||
nBest.add(c);
|
|
||||||
}
|
|
||||||
if (nBest.size() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String bestResult = nBest.get(0).toString();
|
|
||||||
mVoiceInput.logVoiceInputDelivered(bestResult.length());
|
|
||||||
mHints.registerVoiceResult(bestResult);
|
|
||||||
|
|
||||||
if (ic != null) ic.beginBatchEdit(); // To avoid extra updates on committing older text
|
|
||||||
mService.commitTyped(ic, LastComposedWord.NOT_A_SEPARATOR);
|
|
||||||
EditingUtils.appendText(ic, bestResult);
|
|
||||||
if (ic != null) ic.endBatchEdit();
|
|
||||||
|
|
||||||
mVoiceInputHighlighted = true;
|
|
||||||
mWordToSuggestions.putAll(mVoiceResults.alternatives);
|
|
||||||
onCancelVoice();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void switchToRecognitionStatusView(final Configuration configuration) {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// mService.setCandidatesViewShown(false);
|
|
||||||
mRecognizing = true;
|
|
||||||
mVoiceInput.newView();
|
|
||||||
View v = mVoiceInput.getView();
|
|
||||||
|
|
||||||
ViewParent p = v.getParent();
|
|
||||||
if (p != null && p instanceof ViewGroup) {
|
|
||||||
((ViewGroup) p).removeView(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
View keyboardView = KeyboardSwitcher.getInstance().getKeyboardView();
|
|
||||||
|
|
||||||
// The full height of the keyboard is difficult to calculate
|
|
||||||
// as the dimension is expressed in "mm" and not in "pixel"
|
|
||||||
// As we add mm, we don't know how the rounding is going to work
|
|
||||||
// thus we may end up with few pixels extra (or less).
|
|
||||||
if (keyboardView != null) {
|
|
||||||
View popupLayout = v.findViewById(R.id.popup_layout);
|
|
||||||
final int displayHeight =
|
|
||||||
mService.getResources().getDisplayMetrics().heightPixels;
|
|
||||||
final int currentHeight = popupLayout.getLayoutParams().height;
|
|
||||||
final int keyboardHeight = keyboardView.getHeight();
|
|
||||||
if (mMinimumVoiceRecognitionViewHeightPixel > keyboardHeight
|
|
||||||
|| mMinimumVoiceRecognitionViewHeightPixel > currentHeight) {
|
|
||||||
popupLayout.getLayoutParams().height =
|
|
||||||
mMinimumVoiceRecognitionViewHeightPixel;
|
|
||||||
} else if (keyboardHeight > currentHeight || keyboardHeight
|
|
||||||
> (displayHeight / RECOGNITIONVIEW_HEIGHT_THRESHOLD_RATIO)) {
|
|
||||||
popupLayout.getLayoutParams().height = keyboardHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mService.setInputView(v);
|
|
||||||
mService.updateInputViewShown();
|
|
||||||
|
|
||||||
if (configuration != null) {
|
|
||||||
mVoiceInput.onConfigurationChanged(configuration);
|
|
||||||
}
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void switchToLastInputMethod() {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final IBinder token = mService.getWindow().getWindow().getAttributes().token;
|
|
||||||
new AsyncTask<Void, Void, Boolean>() {
|
|
||||||
@Override
|
|
||||||
protected Boolean doInBackground(Void... params) {
|
|
||||||
return mImm.switchToLastInputMethod(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Boolean result) {
|
|
||||||
// Calls in this method need to be done in the same thread as the thread which
|
|
||||||
// called switchToLastInputMethod()
|
|
||||||
if (!result) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "Couldn't switch back to last IME.");
|
|
||||||
}
|
|
||||||
// Because the current IME and subtype failed to switch to any other IME and
|
|
||||||
// subtype by switchToLastInputMethod, the current IME and subtype should keep
|
|
||||||
// being LatinIME and voice subtype in the next time. And for re-showing voice
|
|
||||||
// mode, the state of voice input should be reset and the voice view should be
|
|
||||||
// hidden.
|
|
||||||
mVoiceInput.reset();
|
|
||||||
mService.requestHideSelf(0);
|
|
||||||
} else {
|
|
||||||
// Notify an event that the current subtype was changed. This event will be
|
|
||||||
// handled if "onCurrentInputMethodSubtypeChanged" can't be implemented
|
|
||||||
// when the API level is 10 or previous.
|
|
||||||
mService.notifyOnCurrentInputMethodSubtypeChanged(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void reallyStartListening(boolean swipe) {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!mHasUsedVoiceInput) {
|
|
||||||
// The user has started a voice input, so remember that in the
|
|
||||||
// future (so we don't show the warning dialog after the first run).
|
|
||||||
SharedPreferences.Editor editor =
|
|
||||||
PreferenceManager.getDefaultSharedPreferences(mService).edit();
|
|
||||||
editor.putBoolean(PREF_HAS_USED_VOICE_INPUT, true);
|
|
||||||
SharedPreferencesCompat.apply(editor);
|
|
||||||
mHasUsedVoiceInput = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mLocaleSupportedForVoiceInput && !mHasUsedVoiceInputUnsupportedLocale) {
|
|
||||||
// The user has started a voice input from an unsupported locale, so remember that
|
|
||||||
// in the future (so we don't show the warning dialog the next time they do this).
|
|
||||||
SharedPreferences.Editor editor =
|
|
||||||
PreferenceManager.getDefaultSharedPreferences(mService).edit();
|
|
||||||
editor.putBoolean(PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE, true);
|
|
||||||
SharedPreferencesCompat.apply(editor);
|
|
||||||
mHasUsedVoiceInputUnsupportedLocale = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear N-best suggestions
|
|
||||||
mService.clearSuggestions();
|
|
||||||
|
|
||||||
FieldContext context = makeFieldContext();
|
|
||||||
mVoiceInput.startListening(context, swipe);
|
|
||||||
switchToRecognitionStatusView(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startListening(final boolean swipe, IBinder token) {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// TODO: remove swipe which is no longer used.
|
|
||||||
if (needsToShowWarningDialog()) {
|
|
||||||
// Calls reallyStartListening if user clicks OK, does nothing if user clicks Cancel.
|
|
||||||
showVoiceWarningDialog(swipe, token);
|
|
||||||
} else {
|
|
||||||
reallyStartListening(swipe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean fieldCanDoVoice(FieldContext fieldContext) {
|
|
||||||
return !mPasswordText
|
|
||||||
&& mVoiceInput != null
|
|
||||||
&& !mVoiceInput.isBlacklistedField(fieldContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean shouldShowVoiceButton(FieldContext fieldContext, EditorInfo editorInfo) {
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
final boolean noMic = StringUtils.inPrivateImeOptions(null,
|
|
||||||
LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo)
|
|
||||||
|| StringUtils.inPrivateImeOptions(mService.getPackageName(),
|
|
||||||
LatinIME.IME_OPTION_NO_MICROPHONE, editorInfo);
|
|
||||||
return ENABLE_VOICE_BUTTON && fieldCanDoVoice(fieldContext) && !noMic
|
|
||||||
&& SpeechRecognizer.isRecognitionAvailable(mService);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isRecognitionAvailable(Context context) {
|
|
||||||
return SpeechRecognizer.isRecognitionAvailable(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void loadSettings(EditorInfo editorInfo, SharedPreferences sp) {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mHasUsedVoiceInput = sp.getBoolean(PREF_HAS_USED_VOICE_INPUT, false);
|
|
||||||
mHasUsedVoiceInputUnsupportedLocale =
|
|
||||||
sp.getBoolean(PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE, false);
|
|
||||||
|
|
||||||
mLocaleSupportedForVoiceInput = SubtypeSwitcher.isVoiceSupported(
|
|
||||||
mService, SubtypeSwitcher.getInstance().getInputLocaleStr());
|
|
||||||
|
|
||||||
final String voiceMode = sp.getString(PREF_VOICE_MODE,
|
|
||||||
mService.getString(R.string.voice_mode_main));
|
|
||||||
mVoiceButtonEnabled = !voiceMode.equals(mService.getString(R.string.voice_mode_off))
|
|
||||||
&& shouldShowVoiceButton(makeFieldContext(), editorInfo);
|
|
||||||
mVoiceButtonOnPrimary = voiceMode.equals(mService.getString(R.string.voice_mode_main));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void destroy() {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mVoiceInput != null) {
|
|
||||||
mVoiceInput.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onStartInputView(IBinder keyboardViewToken) {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// If keyboardViewToken is null, keyboardView is not attached but voiceView is attached.
|
|
||||||
IBinder windowToken = keyboardViewToken != null ? keyboardViewToken
|
|
||||||
: mVoiceInput.getView().getWindowToken();
|
|
||||||
// If IME is in voice mode, but still needs to show the voice warning dialog,
|
|
||||||
// keep showing the warning.
|
|
||||||
if (mSubtypeSwitcher.isVoiceMode() && windowToken != null) {
|
|
||||||
// Close keyboard view if it is been shown.
|
|
||||||
final LatinKeyboardView keyboardView = KeyboardSwitcher.getInstance().getKeyboardView();
|
|
||||||
if (keyboardView != null && keyboardView.isShown())
|
|
||||||
keyboardView.purgeKeyboardAndClosing();
|
|
||||||
startListening(false, windowToken);
|
|
||||||
}
|
|
||||||
// If we have no token, onAttachedToWindow will take care of showing dialog and start
|
|
||||||
// listening.
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onAttachedToWindow() {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// After onAttachedToWindow, we can show the voice warning dialog. See startListening()
|
|
||||||
// above.
|
|
||||||
VoiceInputWrapper.getInstance().setVoiceInput(mVoiceInput, mSubtypeSwitcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onConfigurationChanged(Configuration configuration) {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mRecognizing) {
|
|
||||||
switchToRecognitionStatusView(configuration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCancelVoice() {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mRecognizing) {
|
|
||||||
if (mSubtypeSwitcher.isVoiceMode()) {
|
|
||||||
// If voice mode is being canceled within LatinIME (i.e. time-out or user
|
|
||||||
// cancellation etc.), onCancelVoice() will be called first. LatinIME thinks it's
|
|
||||||
// still in voice mode. LatinIME needs to call switchToLastInputMethod().
|
|
||||||
// Note that onCancelVoice() will be called again from SubtypeSwitcher.
|
|
||||||
switchToLastInputMethod();
|
|
||||||
} else if (mSubtypeSwitcher.isKeyboardMode()) {
|
|
||||||
// If voice mode is being canceled out of LatinIME (i.e. by user's IME switching or
|
|
||||||
// as a result of switchToLastInputMethod() etc.),
|
|
||||||
// onCurrentInputMethodSubtypeChanged() will be called first. LatinIME will know
|
|
||||||
// that it's in keyboard mode and SubtypeSwitcher will call onCancelVoice().
|
|
||||||
mRecognizing = false;
|
|
||||||
mService.switchToKeyboardView();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onVoiceResults(List<String> candidates,
|
|
||||||
Map<String, List<CharSequence>> alternatives) {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!mRecognizing) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mVoiceResults.candidates = candidates;
|
|
||||||
mVoiceResults.alternatives = alternatives;
|
|
||||||
mHandler.updateVoiceResults();
|
|
||||||
}
|
|
||||||
|
|
||||||
private FieldContext makeFieldContext() {
|
|
||||||
SubtypeSwitcher switcher = SubtypeSwitcher.getInstance();
|
|
||||||
return new FieldContext(mService.getCurrentInputConnection(),
|
|
||||||
mService.getCurrentInputEditorInfo(), switcher.getInputLocaleStr(),
|
|
||||||
switcher.getEnabledLanguages());
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: make this private (proguard issue)
|
|
||||||
public static class VoiceResults {
|
|
||||||
List<String> candidates;
|
|
||||||
Map<String, List<CharSequence>> alternatives;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class VoiceInputWrapper {
|
|
||||||
private static final VoiceInputWrapper sInputWrapperInstance = new VoiceInputWrapper();
|
|
||||||
private VoiceInput mVoiceInput;
|
|
||||||
public static VoiceInputWrapper getInstance() {
|
|
||||||
return sInputWrapperInstance;
|
|
||||||
}
|
|
||||||
private void setVoiceInput(VoiceInput voiceInput, SubtypeSwitcher switcher) {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mVoiceInput == null && voiceInput != null) {
|
|
||||||
mVoiceInput = voiceInput;
|
|
||||||
}
|
|
||||||
switcher.setVoiceInputWrapper(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private VoiceInputWrapper() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cancel() {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mVoiceInput != null) mVoiceInput.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset() {
|
|
||||||
if (!VOICE_INSTALLED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mVoiceInput != null) mVoiceInput.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A list of locales which are supported by default for voice input, unless we get a
|
|
||||||
// different list from Gservices.
|
|
||||||
private static final String DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES =
|
|
||||||
"en " +
|
|
||||||
"en_US " +
|
|
||||||
"en_GB " +
|
|
||||||
"en_AU " +
|
|
||||||
"en_CA " +
|
|
||||||
"en_IE " +
|
|
||||||
"en_IN " +
|
|
||||||
"en_NZ " +
|
|
||||||
"en_SG " +
|
|
||||||
"en_ZA ";
|
|
||||||
|
|
||||||
public static String getSupportedLocalesString (ContentResolver resolver) {
|
|
||||||
return SettingsUtil.getSettingsString(
|
|
||||||
resolver,
|
|
||||||
SettingsUtil.LATIN_IME_VOICE_INPUT_SUPPORTED_LOCALES,
|
|
||||||
DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startChangingConfiguration() {
|
|
||||||
mConfigurationChanging = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void finishChangingConfiguration() {
|
|
||||||
mConfigurationChanging = false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,36 +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.inputmethod.deprecated.compat;
|
|
||||||
|
|
||||||
import com.android.common.userhappiness.UserHappinessSignals;
|
|
||||||
import com.android.inputmethod.compat.CompatUtils;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
public class VoiceInputLoggerCompatUtils {
|
|
||||||
public static final String EXTRA_TEXT_REPLACED_LENGTH = "length";
|
|
||||||
public static final String EXTRA_BEFORE_N_BEST_CHOOSE = "before";
|
|
||||||
public static final String EXTRA_AFTER_N_BEST_CHOOSE = "after";
|
|
||||||
private static final Method METHOD_UserHappinessSignals_setHasVoiceLoggingInfo =
|
|
||||||
CompatUtils.getMethod(UserHappinessSignals.class, "setHasVoiceLoggingInfo",
|
|
||||||
boolean.class);
|
|
||||||
|
|
||||||
public static void setHasVoiceLoggingInfoCompat(boolean hasLoggingInfo) {
|
|
||||||
CompatUtils.invoke(null, null, METHOD_UserHappinessSignals_setHasVoiceLoggingInfo,
|
|
||||||
hasLoggingInfo);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,255 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2008-2009 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.deprecated.languageswitcher;
|
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.SharedPreferences.Editor;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.preference.CheckBoxPreference;
|
|
||||||
import android.preference.PreferenceActivity;
|
|
||||||
import android.preference.PreferenceGroup;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.util.Pair;
|
|
||||||
|
|
||||||
import com.android.inputmethod.compat.SharedPreferencesCompat;
|
|
||||||
import com.android.inputmethod.keyboard.KeyboardSet;
|
|
||||||
import com.android.inputmethod.latin.DictionaryFactory;
|
|
||||||
import com.android.inputmethod.latin.LocaleUtils;
|
|
||||||
import com.android.inputmethod.latin.R;
|
|
||||||
import com.android.inputmethod.latin.Settings;
|
|
||||||
import com.android.inputmethod.latin.StringUtils;
|
|
||||||
|
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.text.Collator;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
|
|
||||||
public class InputLanguageSelection extends PreferenceActivity {
|
|
||||||
|
|
||||||
private SharedPreferences mPrefs;
|
|
||||||
private String mSelectedLanguages;
|
|
||||||
private HashMap<CheckBoxPreference, Locale> mLocaleMap =
|
|
||||||
new HashMap<CheckBoxPreference, Locale>();
|
|
||||||
|
|
||||||
private static class LocaleEntry implements Comparable<Object> {
|
|
||||||
private static Collator sCollator = Collator.getInstance();
|
|
||||||
|
|
||||||
private String mLabel;
|
|
||||||
public final Locale mLocale;
|
|
||||||
|
|
||||||
public LocaleEntry(String label, Locale locale) {
|
|
||||||
this.mLabel = label;
|
|
||||||
this.mLocale = locale;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return this.mLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(Object o) {
|
|
||||||
return sCollator.compare(this.mLabel, ((LocaleEntry) o).mLabel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle icicle) {
|
|
||||||
super.onCreate(icicle);
|
|
||||||
addPreferencesFromResource(R.xml.language_prefs);
|
|
||||||
// Get the settings preferences
|
|
||||||
mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
|
||||||
mSelectedLanguages = mPrefs.getString(Settings.PREF_SELECTED_LANGUAGES, "");
|
|
||||||
String[] languageList = mSelectedLanguages.split(",");
|
|
||||||
ArrayList<LocaleEntry> availableLanguages = getUniqueLocales();
|
|
||||||
PreferenceGroup parent = getPreferenceScreen();
|
|
||||||
final HashMap<Long, LocaleEntry> dictionaryIdLocaleMap = new HashMap<Long, LocaleEntry>();
|
|
||||||
final TreeMap<LocaleEntry, Boolean> localeHasDictionaryMap =
|
|
||||||
new TreeMap<LocaleEntry, Boolean>();
|
|
||||||
for (int i = 0; i < availableLanguages.size(); i++) {
|
|
||||||
LocaleEntry loc = availableLanguages.get(i);
|
|
||||||
Locale locale = loc.mLocale;
|
|
||||||
final Pair<Long, Boolean> hasDictionaryOrLayout = hasDictionaryOrLayout(locale);
|
|
||||||
final Long dictionaryId = hasDictionaryOrLayout.first;
|
|
||||||
final boolean hasLayout = hasDictionaryOrLayout.second;
|
|
||||||
final boolean hasDictionary = dictionaryId != null;
|
|
||||||
// Add this locale to the supported list if:
|
|
||||||
// 1) this locale has a layout/ 2) this locale has a dictionary
|
|
||||||
// If some locales have no layout but have a same dictionary, the shortest locale
|
|
||||||
// will be added to the supported list.
|
|
||||||
if (!hasLayout && !hasDictionary) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (hasLayout) {
|
|
||||||
localeHasDictionaryMap.put(loc, hasDictionary);
|
|
||||||
}
|
|
||||||
if (!hasDictionary) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (dictionaryIdLocaleMap.containsKey(dictionaryId)) {
|
|
||||||
final String newLocale = locale.toString();
|
|
||||||
final String oldLocale =
|
|
||||||
dictionaryIdLocaleMap.get(dictionaryId).mLocale.toString();
|
|
||||||
// Check if this locale is more appropriate to be the candidate of the input locale.
|
|
||||||
if (oldLocale.length() <= newLocale.length() && !hasLayout) {
|
|
||||||
// Don't add this new locale to the map<dictionary id, locale> if:
|
|
||||||
// 1) the new locale's name is longer than the existing one, and
|
|
||||||
// 2) the new locale doesn't have its layout
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dictionaryIdLocaleMap.put(dictionaryId, loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (LocaleEntry localeEntry : dictionaryIdLocaleMap.values()) {
|
|
||||||
if (!localeHasDictionaryMap.containsKey(localeEntry)) {
|
|
||||||
localeHasDictionaryMap.put(localeEntry, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Entry<LocaleEntry, Boolean> entry : localeHasDictionaryMap.entrySet()) {
|
|
||||||
final LocaleEntry localeEntry = entry.getKey();
|
|
||||||
final Locale locale = localeEntry.mLocale;
|
|
||||||
final Boolean hasDictionary = entry.getValue();
|
|
||||||
CheckBoxPreference pref = new CheckBoxPreference(this);
|
|
||||||
pref.setTitle(localeEntry.mLabel);
|
|
||||||
boolean checked = isLocaleIn(locale, languageList);
|
|
||||||
pref.setChecked(checked);
|
|
||||||
if (hasDictionary) {
|
|
||||||
pref.setSummary(R.string.has_dictionary);
|
|
||||||
}
|
|
||||||
mLocaleMap.put(pref, locale);
|
|
||||||
parent.addPreference(pref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isLocaleIn(Locale locale, String[] list) {
|
|
||||||
String lang = get5Code(locale);
|
|
||||||
for (int i = 0; i < list.length; i++) {
|
|
||||||
if (lang.equalsIgnoreCase(list[i])) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Pair<Long, Boolean> hasDictionaryOrLayout(Locale locale) {
|
|
||||||
if (locale == null) return new Pair<Long, Boolean>(null, false);
|
|
||||||
final Resources res = getResources();
|
|
||||||
final Locale saveLocale = LocaleUtils.setSystemLocale(res, locale);
|
|
||||||
final Long dictionaryId = DictionaryFactory.getDictionaryId(this, locale);
|
|
||||||
boolean hasLayout = false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
final String localeStr = locale.toString();
|
|
||||||
final String[] layoutCountryCodes = KeyboardSet.parseKeyboardLocale(
|
|
||||||
getResources(), R.xml.keyboard_set).split(",", -1);
|
|
||||||
if (!TextUtils.isEmpty(localeStr) && layoutCountryCodes.length > 0) {
|
|
||||||
for (String s : layoutCountryCodes) {
|
|
||||||
if (s.equals(localeStr)) {
|
|
||||||
hasLayout = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (XmlPullParserException e) {
|
|
||||||
} catch (IOException e) {
|
|
||||||
}
|
|
||||||
LocaleUtils.setSystemLocale(res, saveLocale);
|
|
||||||
return new Pair<Long, Boolean>(dictionaryId, hasLayout);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String get5Code(Locale locale) {
|
|
||||||
String country = locale.getCountry();
|
|
||||||
return locale.getLanguage()
|
|
||||||
+ (TextUtils.isEmpty(country) ? "" : "_" + country);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
// Save the selected languages
|
|
||||||
String checkedLanguages = "";
|
|
||||||
PreferenceGroup parent = getPreferenceScreen();
|
|
||||||
int count = parent.getPreferenceCount();
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
CheckBoxPreference pref = (CheckBoxPreference) parent.getPreference(i);
|
|
||||||
if (pref.isChecked()) {
|
|
||||||
checkedLanguages += get5Code(mLocaleMap.get(pref)) + ",";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (checkedLanguages.length() < 1) checkedLanguages = null; // Save null
|
|
||||||
Editor editor = mPrefs.edit();
|
|
||||||
editor.putString(Settings.PREF_SELECTED_LANGUAGES, checkedLanguages);
|
|
||||||
SharedPreferencesCompat.apply(editor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<LocaleEntry> getUniqueLocales() {
|
|
||||||
String[] locales = getAssets().getLocales();
|
|
||||||
Arrays.sort(locales);
|
|
||||||
ArrayList<LocaleEntry> uniqueLocales = new ArrayList<LocaleEntry>();
|
|
||||||
|
|
||||||
final int origSize = locales.length;
|
|
||||||
LocaleEntry[] preprocess = new LocaleEntry[origSize];
|
|
||||||
int finalSize = 0;
|
|
||||||
for (int i = 0 ; i < origSize; i++ ) {
|
|
||||||
String s = locales[i];
|
|
||||||
int len = s.length();
|
|
||||||
String language = "";
|
|
||||||
String country = "";
|
|
||||||
if (len == 5) {
|
|
||||||
language = s.substring(0, 2);
|
|
||||||
country = s.substring(3, 5);
|
|
||||||
} else if (len < 5) {
|
|
||||||
language = s;
|
|
||||||
}
|
|
||||||
Locale l = new Locale(language, country);
|
|
||||||
|
|
||||||
// Exclude languages that are not relevant to LatinIME
|
|
||||||
if (TextUtils.isEmpty(language)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (finalSize == 0) {
|
|
||||||
preprocess[finalSize++] =
|
|
||||||
new LocaleEntry(StringUtils.getFullDisplayName(l, false), l);
|
|
||||||
} else {
|
|
||||||
if (s.equals("zz_ZZ")) {
|
|
||||||
// ignore this locale
|
|
||||||
} else {
|
|
||||||
final String displayName = StringUtils.getFullDisplayName(l, false);
|
|
||||||
preprocess[finalSize++] = new LocaleEntry(displayName, l);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = 0; i < finalSize ; i++) {
|
|
||||||
uniqueLocales.add(preprocess[i]);
|
|
||||||
}
|
|
||||||
return uniqueLocales;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,234 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2010 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.inputmethod.deprecated.languageswitcher;
|
|
||||||
|
|
||||||
import com.android.inputmethod.compat.SharedPreferencesCompat;
|
|
||||||
import com.android.inputmethod.latin.LatinIME;
|
|
||||||
import com.android.inputmethod.latin.LatinImeLogger;
|
|
||||||
import com.android.inputmethod.latin.LocaleUtils;
|
|
||||||
import com.android.inputmethod.latin.Settings;
|
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.SharedPreferences.Editor;
|
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Keeps track of list of selected input languages and the current
|
|
||||||
* input language that the user has selected.
|
|
||||||
*/
|
|
||||||
public class LanguageSwitcher {
|
|
||||||
private static final String TAG = LanguageSwitcher.class.getSimpleName();
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private static final String KEYBOARD_MODE = "keyboard";
|
|
||||||
private static final String[] EMPTY_STIRNG_ARRAY = new String[0];
|
|
||||||
|
|
||||||
private final ArrayList<Locale> mLocales = new ArrayList<Locale>();
|
|
||||||
private final LatinIME mIme;
|
|
||||||
private String[] mSelectedLanguageArray = EMPTY_STIRNG_ARRAY;
|
|
||||||
private String mSelectedLanguages;
|
|
||||||
private int mCurrentIndex = 0;
|
|
||||||
private String mDefaultInputLanguage;
|
|
||||||
private Locale mDefaultInputLocale;
|
|
||||||
private Locale mSystemLocale;
|
|
||||||
|
|
||||||
public LanguageSwitcher(LatinIME ime) {
|
|
||||||
mIme = ime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLocaleCount() {
|
|
||||||
return mLocales.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onConfigurationChanged(Configuration conf, SharedPreferences prefs) {
|
|
||||||
final Locale newLocale = conf.locale;
|
|
||||||
if (!getSystemLocale().toString().equals(newLocale.toString())) {
|
|
||||||
loadLocales(prefs, newLocale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the currently selected input languages from shared preferences.
|
|
||||||
* @param sp shared preference for getting the current input language and enabled languages
|
|
||||||
* @param systemLocale the current system locale, stored for changing the current input language
|
|
||||||
* based on the system current system locale.
|
|
||||||
* @return whether there was any change
|
|
||||||
*/
|
|
||||||
public boolean loadLocales(SharedPreferences sp, Locale systemLocale) {
|
|
||||||
if (LatinImeLogger.sDBG) {
|
|
||||||
Log.d(TAG, "load locales");
|
|
||||||
}
|
|
||||||
if (systemLocale != null) {
|
|
||||||
setSystemLocale(systemLocale);
|
|
||||||
}
|
|
||||||
String selectedLanguages = sp.getString(Settings.PREF_SELECTED_LANGUAGES, null);
|
|
||||||
String currentLanguage = sp.getString(Settings.PREF_INPUT_LANGUAGE, null);
|
|
||||||
if (TextUtils.isEmpty(selectedLanguages)) {
|
|
||||||
mSelectedLanguageArray = EMPTY_STIRNG_ARRAY;
|
|
||||||
mSelectedLanguages = null;
|
|
||||||
loadDefaults();
|
|
||||||
if (mLocales.size() == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
mLocales.clear();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (selectedLanguages.equals(mSelectedLanguages)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
mSelectedLanguageArray = selectedLanguages.split(",");
|
|
||||||
mSelectedLanguages = selectedLanguages; // Cache it for comparison later
|
|
||||||
constructLocales();
|
|
||||||
mCurrentIndex = 0;
|
|
||||||
if (currentLanguage != null) {
|
|
||||||
// Find the index
|
|
||||||
mCurrentIndex = 0;
|
|
||||||
for (int i = 0; i < mLocales.size(); i++) {
|
|
||||||
if (mSelectedLanguageArray[i].equals(currentLanguage)) {
|
|
||||||
mCurrentIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If we didn't find the index, use the first one
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadDefaults() {
|
|
||||||
if (LatinImeLogger.sDBG) {
|
|
||||||
Log.d(TAG, "load default locales:");
|
|
||||||
}
|
|
||||||
mDefaultInputLocale = mIme.getResources().getConfiguration().locale;
|
|
||||||
String country = mDefaultInputLocale.getCountry();
|
|
||||||
mDefaultInputLanguage = mDefaultInputLocale.getLanguage() +
|
|
||||||
(TextUtils.isEmpty(country) ? "" : "_" + country);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void constructLocales() {
|
|
||||||
mLocales.clear();
|
|
||||||
for (final String lang : mSelectedLanguageArray) {
|
|
||||||
final Locale locale = LocaleUtils.constructLocaleFromString(lang);
|
|
||||||
mLocales.add(locale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the currently selected input language code, or the display language code if
|
|
||||||
* no specific locale was selected for input.
|
|
||||||
*/
|
|
||||||
public String getInputLanguage() {
|
|
||||||
if (getLocaleCount() == 0) return mDefaultInputLanguage;
|
|
||||||
|
|
||||||
return mSelectedLanguageArray[mCurrentIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the list of enabled language codes.
|
|
||||||
*/
|
|
||||||
public String[] getEnabledLanguages(boolean allowImplicitlySelectedLanguages) {
|
|
||||||
if (mSelectedLanguageArray.length == 0 && allowImplicitlySelectedLanguages) {
|
|
||||||
return new String[] { mDefaultInputLanguage };
|
|
||||||
}
|
|
||||||
return mSelectedLanguageArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the currently selected input locale, or the display locale if no specific
|
|
||||||
* locale was selected for input.
|
|
||||||
*/
|
|
||||||
public Locale getInputLocale() {
|
|
||||||
if (getLocaleCount() == 0) return mDefaultInputLocale;
|
|
||||||
|
|
||||||
return mLocales.get(mCurrentIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int nextLocaleIndex() {
|
|
||||||
final int size = mLocales.size();
|
|
||||||
return (mCurrentIndex + 1) % size;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int prevLocaleIndex() {
|
|
||||||
final int size = mLocales.size();
|
|
||||||
return (mCurrentIndex - 1 + size) % size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the next input locale in the list. Wraps around to the beginning of the
|
|
||||||
* list if we're at the end of the list.
|
|
||||||
*/
|
|
||||||
public Locale getNextInputLocale() {
|
|
||||||
if (getLocaleCount() == 0) return mDefaultInputLocale;
|
|
||||||
return mLocales.get(nextLocaleIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the system locale (display UI) used for comparing with the input language.
|
|
||||||
* @param locale the locale of the system
|
|
||||||
*/
|
|
||||||
private void setSystemLocale(Locale locale) {
|
|
||||||
mSystemLocale = locale;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the system locale.
|
|
||||||
* @return the system locale
|
|
||||||
*/
|
|
||||||
private Locale getSystemLocale() {
|
|
||||||
return mSystemLocale;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the previous input locale in the list. Wraps around to the end of the
|
|
||||||
* list if we're at the beginning of the list.
|
|
||||||
*/
|
|
||||||
public Locale getPrevInputLocale() {
|
|
||||||
if (getLocaleCount() == 0) return mDefaultInputLocale;
|
|
||||||
return mLocales.get(prevLocaleIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset() {
|
|
||||||
mCurrentIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void next() {
|
|
||||||
mCurrentIndex = nextLocaleIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void prev() {
|
|
||||||
mCurrentIndex = prevLocaleIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLocale(String localeStr) {
|
|
||||||
final int N = mLocales.size();
|
|
||||||
for (int i = 0; i < N; ++i) {
|
|
||||||
if (mLocales.get(i).toString().equals(localeStr)) {
|
|
||||||
mCurrentIndex = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void persist(SharedPreferences prefs) {
|
|
||||||
Editor editor = prefs.edit();
|
|
||||||
editor.putString(Settings.PREF_INPUT_LANGUAGE, getInputLanguage());
|
|
||||||
SharedPreferencesCompat.apply(editor);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,104 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2009 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.deprecated.voice;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.inputmethod.EditorInfo;
|
|
||||||
import android.view.inputmethod.ExtractedText;
|
|
||||||
import android.view.inputmethod.ExtractedTextRequest;
|
|
||||||
import android.view.inputmethod.InputConnection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents information about a given text field, which can be passed
|
|
||||||
* to the speech recognizer as context information.
|
|
||||||
*/
|
|
||||||
public class FieldContext {
|
|
||||||
private static final boolean DBG = false;
|
|
||||||
|
|
||||||
static final String LABEL = "label";
|
|
||||||
static final String HINT = "hint";
|
|
||||||
static final String PACKAGE_NAME = "packageName";
|
|
||||||
static final String FIELD_ID = "fieldId";
|
|
||||||
static final String FIELD_NAME = "fieldName";
|
|
||||||
static final String SINGLE_LINE = "singleLine";
|
|
||||||
static final String INPUT_TYPE = "inputType";
|
|
||||||
static final String IME_OPTIONS = "imeOptions";
|
|
||||||
static final String SELECTED_LANGUAGE = "selectedLanguage";
|
|
||||||
static final String ENABLED_LANGUAGES = "enabledLanguages";
|
|
||||||
|
|
||||||
Bundle mFieldInfo;
|
|
||||||
|
|
||||||
public FieldContext(InputConnection conn, EditorInfo editorInfo,
|
|
||||||
String selectedLanguage, String[] enabledLanguages) {
|
|
||||||
mFieldInfo = new Bundle();
|
|
||||||
addEditorInfoToBundle(editorInfo, mFieldInfo);
|
|
||||||
addInputConnectionToBundle(conn, mFieldInfo);
|
|
||||||
addLanguageInfoToBundle(selectedLanguage, enabledLanguages, mFieldInfo);
|
|
||||||
if (DBG) Log.i("FieldContext", "Bundle = " + mFieldInfo.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String safeToString(Object o) {
|
|
||||||
if (o == null) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return o.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addEditorInfoToBundle(EditorInfo info, Bundle bundle) {
|
|
||||||
if (info == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bundle.putString(LABEL, safeToString(info.label));
|
|
||||||
bundle.putString(HINT, safeToString(info.hintText));
|
|
||||||
bundle.putString(PACKAGE_NAME, safeToString(info.packageName));
|
|
||||||
bundle.putInt(FIELD_ID, info.fieldId);
|
|
||||||
bundle.putString(FIELD_NAME, safeToString(info.fieldName));
|
|
||||||
bundle.putInt(INPUT_TYPE, info.inputType);
|
|
||||||
bundle.putInt(IME_OPTIONS, info.imeOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("static-access")
|
|
||||||
private static void addInputConnectionToBundle(
|
|
||||||
InputConnection conn, Bundle bundle) {
|
|
||||||
if (conn == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExtractedText et = conn.getExtractedText(new ExtractedTextRequest(), 0);
|
|
||||||
if (et == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bundle.putBoolean(SINGLE_LINE, (et.flags & et.FLAG_SINGLE_LINE) > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addLanguageInfoToBundle(
|
|
||||||
String selectedLanguage, String[] enabledLanguages, Bundle bundle) {
|
|
||||||
bundle.putString(SELECTED_LANGUAGE, selectedLanguage);
|
|
||||||
bundle.putStringArray(ENABLED_LANGUAGES, enabledLanguages);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bundle getBundle() {
|
|
||||||
return mFieldInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return mFieldInfo.toString();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,188 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2009 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.deprecated.voice;
|
|
||||||
|
|
||||||
import com.android.inputmethod.compat.SharedPreferencesCompat;
|
|
||||||
import com.android.inputmethod.latin.R;
|
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.view.inputmethod.InputConnection;
|
|
||||||
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logic to determine when to display hints on usage to the user.
|
|
||||||
*/
|
|
||||||
public class Hints {
|
|
||||||
public interface Display {
|
|
||||||
public void showHint(int viewResource);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN =
|
|
||||||
"voice_hint_num_unique_days_shown";
|
|
||||||
private static final String PREF_VOICE_HINT_LAST_TIME_SHOWN =
|
|
||||||
"voice_hint_last_time_shown";
|
|
||||||
private static final String PREF_VOICE_INPUT_LAST_TIME_USED =
|
|
||||||
"voice_input_last_time_used";
|
|
||||||
private static final String PREF_VOICE_PUNCTUATION_HINT_VIEW_COUNT =
|
|
||||||
"voice_punctuation_hint_view_count";
|
|
||||||
private static final int DEFAULT_SWIPE_HINT_MAX_DAYS_TO_SHOW = 7;
|
|
||||||
private static final int DEFAULT_PUNCTUATION_HINT_MAX_DISPLAYS = 7;
|
|
||||||
|
|
||||||
private final Context mContext;
|
|
||||||
private final SharedPreferences mPrefs;
|
|
||||||
private final Display mDisplay;
|
|
||||||
private boolean mVoiceResultContainedPunctuation;
|
|
||||||
private int mSwipeHintMaxDaysToShow;
|
|
||||||
private int mPunctuationHintMaxDisplays;
|
|
||||||
|
|
||||||
// Only show punctuation hint if voice result did not contain punctuation.
|
|
||||||
static final Map<CharSequence, String> SPEAKABLE_PUNCTUATION
|
|
||||||
= new HashMap<CharSequence, String>();
|
|
||||||
static {
|
|
||||||
SPEAKABLE_PUNCTUATION.put(",", "comma");
|
|
||||||
SPEAKABLE_PUNCTUATION.put(".", "period");
|
|
||||||
SPEAKABLE_PUNCTUATION.put("?", "question mark");
|
|
||||||
}
|
|
||||||
|
|
||||||
public Hints(Context context, SharedPreferences prefs, Display display) {
|
|
||||||
mContext = context;
|
|
||||||
mPrefs = prefs;
|
|
||||||
mDisplay = display;
|
|
||||||
|
|
||||||
ContentResolver cr = mContext.getContentResolver();
|
|
||||||
mSwipeHintMaxDaysToShow = SettingsUtil.getSettingsInt(
|
|
||||||
cr,
|
|
||||||
SettingsUtil.LATIN_IME_VOICE_INPUT_SWIPE_HINT_MAX_DAYS,
|
|
||||||
DEFAULT_SWIPE_HINT_MAX_DAYS_TO_SHOW);
|
|
||||||
mPunctuationHintMaxDisplays = SettingsUtil.getSettingsInt(
|
|
||||||
cr,
|
|
||||||
SettingsUtil.LATIN_IME_VOICE_INPUT_PUNCTUATION_HINT_MAX_DISPLAYS,
|
|
||||||
DEFAULT_PUNCTUATION_HINT_MAX_DISPLAYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean showSwipeHintIfNecessary(boolean fieldRecommended) {
|
|
||||||
if (fieldRecommended && shouldShowSwipeHint()) {
|
|
||||||
showHint(R.layout.voice_swipe_hint);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean showPunctuationHintIfNecessary(InputConnection ic) {
|
|
||||||
if (!mVoiceResultContainedPunctuation
|
|
||||||
&& ic != null
|
|
||||||
&& getAndIncrementPref(PREF_VOICE_PUNCTUATION_HINT_VIEW_COUNT)
|
|
||||||
< mPunctuationHintMaxDisplays) {
|
|
||||||
CharSequence charBeforeCursor = ic.getTextBeforeCursor(1, 0);
|
|
||||||
if (SPEAKABLE_PUNCTUATION.containsKey(charBeforeCursor)) {
|
|
||||||
showHint(R.layout.voice_punctuation_hint);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerVoiceResult(String text) {
|
|
||||||
// Update the current time as the last time voice input was used.
|
|
||||||
SharedPreferences.Editor editor = mPrefs.edit();
|
|
||||||
editor.putLong(PREF_VOICE_INPUT_LAST_TIME_USED, System.currentTimeMillis());
|
|
||||||
SharedPreferencesCompat.apply(editor);
|
|
||||||
|
|
||||||
mVoiceResultContainedPunctuation = false;
|
|
||||||
for (CharSequence s : SPEAKABLE_PUNCTUATION.keySet()) {
|
|
||||||
if (text.indexOf(s.toString()) >= 0) {
|
|
||||||
mVoiceResultContainedPunctuation = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean shouldShowSwipeHint() {
|
|
||||||
final SharedPreferences prefs = mPrefs;
|
|
||||||
|
|
||||||
int numUniqueDaysShown = prefs.getInt(PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN, 0);
|
|
||||||
|
|
||||||
// If we've already shown the hint for enough days, we'll return false.
|
|
||||||
if (numUniqueDaysShown < mSwipeHintMaxDaysToShow) {
|
|
||||||
|
|
||||||
long lastTimeVoiceWasUsed = prefs.getLong(PREF_VOICE_INPUT_LAST_TIME_USED, 0);
|
|
||||||
|
|
||||||
// If the user has used voice today, we'll return false. (We don't show the hint on
|
|
||||||
// any day that the user has already used voice.)
|
|
||||||
if (!isFromToday(lastTimeVoiceWasUsed)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines whether the provided time is from some time today (i.e., this day, month,
|
|
||||||
* and year).
|
|
||||||
*/
|
|
||||||
private boolean isFromToday(long timeInMillis) {
|
|
||||||
if (timeInMillis == 0) return false;
|
|
||||||
|
|
||||||
Calendar today = Calendar.getInstance();
|
|
||||||
today.setTimeInMillis(System.currentTimeMillis());
|
|
||||||
|
|
||||||
Calendar timestamp = Calendar.getInstance();
|
|
||||||
timestamp.setTimeInMillis(timeInMillis);
|
|
||||||
|
|
||||||
return (today.get(Calendar.YEAR) == timestamp.get(Calendar.YEAR) &&
|
|
||||||
today.get(Calendar.DAY_OF_MONTH) == timestamp.get(Calendar.DAY_OF_MONTH) &&
|
|
||||||
today.get(Calendar.MONTH) == timestamp.get(Calendar.MONTH));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showHint(int hintViewResource) {
|
|
||||||
final SharedPreferences prefs = mPrefs;
|
|
||||||
|
|
||||||
int numUniqueDaysShown = prefs.getInt(PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN, 0);
|
|
||||||
long lastTimeHintWasShown = prefs.getLong(PREF_VOICE_HINT_LAST_TIME_SHOWN, 0);
|
|
||||||
|
|
||||||
// If this is the first time the hint is being shown today, increase the saved values
|
|
||||||
// to represent that. We don't need to increase the last time the hint was shown unless
|
|
||||||
// it is a different day from the current value.
|
|
||||||
if (!isFromToday(lastTimeHintWasShown)) {
|
|
||||||
SharedPreferences.Editor editor = prefs.edit();
|
|
||||||
editor.putInt(PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN, numUniqueDaysShown + 1);
|
|
||||||
editor.putLong(PREF_VOICE_HINT_LAST_TIME_SHOWN, System.currentTimeMillis());
|
|
||||||
SharedPreferencesCompat.apply(editor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mDisplay != null) {
|
|
||||||
mDisplay.showHint(hintViewResource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getAndIncrementPref(String pref) {
|
|
||||||
final SharedPreferences prefs = mPrefs;
|
|
||||||
int value = prefs.getInt(pref, 0);
|
|
||||||
SharedPreferences.Editor editor = prefs.edit();
|
|
||||||
editor.putInt(pref, value + 1);
|
|
||||||
SharedPreferencesCompat.apply(editor);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,355 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2009 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.deprecated.voice;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.CornerPathEffect;
|
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.graphics.Path;
|
|
||||||
import android.graphics.PathEffect;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.ProgressBar;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import com.android.inputmethod.latin.R;
|
|
||||||
import com.android.inputmethod.latin.StringUtils;
|
|
||||||
import com.android.inputmethod.latin.SubtypeSwitcher;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
import java.nio.ShortBuffer;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The user interface for the "Speak now" and "working" states.
|
|
||||||
* Displays a recognition dialog (with waveform, voice meter, etc.),
|
|
||||||
* plays beeps, shows errors, etc.
|
|
||||||
*/
|
|
||||||
public class RecognitionView {
|
|
||||||
private static final String TAG = "RecognitionView";
|
|
||||||
|
|
||||||
private Handler mUiHandler; // Reference to UI thread
|
|
||||||
private View mView;
|
|
||||||
private Context mContext;
|
|
||||||
|
|
||||||
private TextView mText;
|
|
||||||
private ImageView mImage;
|
|
||||||
private View mProgress;
|
|
||||||
private SoundIndicator mSoundIndicator;
|
|
||||||
private TextView mLanguage;
|
|
||||||
private Button mButton;
|
|
||||||
|
|
||||||
private Drawable mInitializing;
|
|
||||||
private Drawable mError;
|
|
||||||
|
|
||||||
private static final int INIT = 0;
|
|
||||||
private static final int LISTENING = 1;
|
|
||||||
private static final int WORKING = 2;
|
|
||||||
private static final int READY = 3;
|
|
||||||
|
|
||||||
private int mState = INIT;
|
|
||||||
|
|
||||||
private final View mPopupLayout;
|
|
||||||
|
|
||||||
private final Drawable mListeningBorder;
|
|
||||||
private final Drawable mWorkingBorder;
|
|
||||||
private final Drawable mErrorBorder;
|
|
||||||
|
|
||||||
public RecognitionView(Context context, OnClickListener clickListener) {
|
|
||||||
mUiHandler = new Handler();
|
|
||||||
|
|
||||||
LayoutInflater inflater = (LayoutInflater) context.getSystemService(
|
|
||||||
Context.LAYOUT_INFLATER_SERVICE);
|
|
||||||
|
|
||||||
mView = inflater.inflate(R.layout.recognition_status, null);
|
|
||||||
|
|
||||||
mPopupLayout= mView.findViewById(R.id.popup_layout);
|
|
||||||
|
|
||||||
// Pre-load volume level images
|
|
||||||
Resources r = context.getResources();
|
|
||||||
|
|
||||||
mListeningBorder = r.getDrawable(R.drawable.vs_dialog_red);
|
|
||||||
mWorkingBorder = r.getDrawable(R.drawable.vs_dialog_blue);
|
|
||||||
mErrorBorder = r.getDrawable(R.drawable.vs_dialog_yellow);
|
|
||||||
|
|
||||||
mInitializing = r.getDrawable(R.drawable.mic_slash);
|
|
||||||
mError = r.getDrawable(R.drawable.caution);
|
|
||||||
|
|
||||||
mImage = (ImageView) mView.findViewById(R.id.image);
|
|
||||||
mProgress = mView.findViewById(R.id.progress);
|
|
||||||
mSoundIndicator = (SoundIndicator) mView.findViewById(R.id.sound_indicator);
|
|
||||||
|
|
||||||
mButton = (Button) mView.findViewById(R.id.button);
|
|
||||||
mButton.setOnClickListener(clickListener);
|
|
||||||
mText = (TextView) mView.findViewById(R.id.text);
|
|
||||||
mLanguage = (TextView) mView.findViewById(R.id.language);
|
|
||||||
|
|
||||||
mContext = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
public View getView() {
|
|
||||||
return mView;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void restoreState() {
|
|
||||||
mUiHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// Restart the spinner
|
|
||||||
if (mState == WORKING) {
|
|
||||||
((ProgressBar) mProgress).setIndeterminate(false);
|
|
||||||
((ProgressBar) mProgress).setIndeterminate(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showInitializing() {
|
|
||||||
mUiHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
mState = INIT;
|
|
||||||
prepareDialog(mContext.getText(R.string.voice_initializing), mInitializing,
|
|
||||||
mContext.getText(R.string.cancel));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showListening() {
|
|
||||||
Log.d(TAG, "#showListening");
|
|
||||||
mUiHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
mState = LISTENING;
|
|
||||||
prepareDialog(mContext.getText(R.string.voice_listening), null,
|
|
||||||
mContext.getText(R.string.cancel));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateVoiceMeter(float rmsdB) {
|
|
||||||
mSoundIndicator.setRmsdB(rmsdB);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showError(final String message) {
|
|
||||||
mUiHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
mState = READY;
|
|
||||||
prepareDialog(message, mError, mContext.getText(R.string.ok));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showWorking(
|
|
||||||
final ByteArrayOutputStream waveBuffer,
|
|
||||||
final int speechStartPosition,
|
|
||||||
final int speechEndPosition) {
|
|
||||||
mUiHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
mState = WORKING;
|
|
||||||
prepareDialog(mContext.getText(R.string.voice_working), null, mContext
|
|
||||||
.getText(R.string.cancel));
|
|
||||||
final ShortBuffer buf = ByteBuffer.wrap(waveBuffer.toByteArray()).order(
|
|
||||||
ByteOrder.nativeOrder()).asShortBuffer();
|
|
||||||
buf.position(0);
|
|
||||||
waveBuffer.reset();
|
|
||||||
showWave(buf, speechStartPosition / 2, speechEndPosition / 2);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void prepareDialog(CharSequence text, Drawable image,
|
|
||||||
CharSequence btnTxt) {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The mic of INIT and of LISTENING has to be displayed in the same position. To accomplish
|
|
||||||
* that, some text visibility are not set as GONE but as INVISIBLE.
|
|
||||||
*/
|
|
||||||
switch (mState) {
|
|
||||||
case INIT:
|
|
||||||
mText.setVisibility(View.INVISIBLE);
|
|
||||||
|
|
||||||
mProgress.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
mImage.setVisibility(View.VISIBLE);
|
|
||||||
mImage.setImageResource(R.drawable.mic_slash);
|
|
||||||
|
|
||||||
mSoundIndicator.setVisibility(View.GONE);
|
|
||||||
mSoundIndicator.stop();
|
|
||||||
|
|
||||||
mLanguage.setVisibility(View.INVISIBLE);
|
|
||||||
|
|
||||||
mPopupLayout.setBackgroundDrawable(mListeningBorder);
|
|
||||||
break;
|
|
||||||
case LISTENING:
|
|
||||||
mText.setVisibility(View.VISIBLE);
|
|
||||||
mText.setText(text);
|
|
||||||
|
|
||||||
mProgress.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
mImage.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
mSoundIndicator.setVisibility(View.VISIBLE);
|
|
||||||
mSoundIndicator.start();
|
|
||||||
|
|
||||||
Locale locale = SubtypeSwitcher.getInstance().getInputLocale();
|
|
||||||
|
|
||||||
mLanguage.setVisibility(View.VISIBLE);
|
|
||||||
mLanguage.setText(StringUtils.getFullDisplayName(locale, true));
|
|
||||||
|
|
||||||
mPopupLayout.setBackgroundDrawable(mListeningBorder);
|
|
||||||
break;
|
|
||||||
case WORKING:
|
|
||||||
|
|
||||||
mText.setVisibility(View.VISIBLE);
|
|
||||||
mText.setText(text);
|
|
||||||
|
|
||||||
mProgress.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
mImage.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
mSoundIndicator.setVisibility(View.GONE);
|
|
||||||
mSoundIndicator.stop();
|
|
||||||
|
|
||||||
mLanguage.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
mPopupLayout.setBackgroundDrawable(mWorkingBorder);
|
|
||||||
break;
|
|
||||||
case READY:
|
|
||||||
mText.setVisibility(View.VISIBLE);
|
|
||||||
mText.setText(text);
|
|
||||||
|
|
||||||
mProgress.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
mImage.setVisibility(View.VISIBLE);
|
|
||||||
mImage.setImageResource(R.drawable.caution);
|
|
||||||
|
|
||||||
mSoundIndicator.setVisibility(View.GONE);
|
|
||||||
mSoundIndicator.stop();
|
|
||||||
|
|
||||||
mLanguage.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
mPopupLayout.setBackgroundDrawable(mErrorBorder);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Log.w(TAG, "Unknown state " + mState);
|
|
||||||
}
|
|
||||||
mPopupLayout.requestLayout();
|
|
||||||
mButton.setText(btnTxt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return an average abs of the specified buffer.
|
|
||||||
*/
|
|
||||||
private static int getAverageAbs(ShortBuffer buffer, int start, int i, int npw) {
|
|
||||||
int from = start + i * npw;
|
|
||||||
int end = from + npw;
|
|
||||||
int total = 0;
|
|
||||||
for (int x = from; x < end; x++) {
|
|
||||||
total += Math.abs(buffer.get(x));
|
|
||||||
}
|
|
||||||
return total / npw;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows waveform of input audio.
|
|
||||||
*
|
|
||||||
* Copied from version in VoiceSearch's RecognitionActivity.
|
|
||||||
*
|
|
||||||
* TODO: adjust stroke width based on the size of data.
|
|
||||||
* TODO: use dip rather than pixels.
|
|
||||||
*/
|
|
||||||
private void showWave(ShortBuffer waveBuffer, int startPosition, int endPosition) {
|
|
||||||
final int w = ((View) mImage.getParent()).getWidth();
|
|
||||||
final int h = ((View) mImage.getParent()).getHeight();
|
|
||||||
if (w <= 0 || h <= 0) {
|
|
||||||
// view is not visible this time. Skip drawing.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
|
|
||||||
final Canvas c = new Canvas(b);
|
|
||||||
final Paint paint = new Paint();
|
|
||||||
paint.setColor(0xFFFFFFFF); // 0xAARRGGBB
|
|
||||||
paint.setAntiAlias(true);
|
|
||||||
paint.setStyle(Paint.Style.STROKE);
|
|
||||||
paint.setAlpha(80);
|
|
||||||
|
|
||||||
final PathEffect effect = new CornerPathEffect(3);
|
|
||||||
paint.setPathEffect(effect);
|
|
||||||
|
|
||||||
final int numSamples = waveBuffer.remaining();
|
|
||||||
int endIndex;
|
|
||||||
if (endPosition == 0) {
|
|
||||||
endIndex = numSamples;
|
|
||||||
} else {
|
|
||||||
endIndex = Math.min(endPosition, numSamples);
|
|
||||||
}
|
|
||||||
|
|
||||||
int startIndex = startPosition - 2000; // include 250ms before speech
|
|
||||||
if (startIndex < 0) {
|
|
||||||
startIndex = 0;
|
|
||||||
}
|
|
||||||
final int numSamplePerWave = 200; // 8KHz 25ms = 200 samples
|
|
||||||
final float scale = 10.0f / 65536.0f;
|
|
||||||
|
|
||||||
final int count = (endIndex - startIndex) / numSamplePerWave;
|
|
||||||
final float deltaX = 1.0f * w / count;
|
|
||||||
int yMax = h / 2;
|
|
||||||
Path path = new Path();
|
|
||||||
c.translate(0, yMax);
|
|
||||||
float x = 0;
|
|
||||||
path.moveTo(x, 0);
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
final int avabs = getAverageAbs(waveBuffer, startIndex, i , numSamplePerWave);
|
|
||||||
int sign = ( (i & 01) == 0) ? -1 : 1;
|
|
||||||
final float y = Math.min(yMax, avabs * h * scale) * sign;
|
|
||||||
path.lineTo(x, y);
|
|
||||||
x += deltaX;
|
|
||||||
path.lineTo(x, y);
|
|
||||||
}
|
|
||||||
if (deltaX > 4) {
|
|
||||||
paint.setStrokeWidth(2);
|
|
||||||
} else {
|
|
||||||
paint.setStrokeWidth(Math.max(0, (int) (deltaX -.05)));
|
|
||||||
}
|
|
||||||
c.drawPath(path, paint);
|
|
||||||
mImage.setImageBitmap(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void finish() {
|
|
||||||
mUiHandler.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
mSoundIndicator.stop();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,110 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2009 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.deprecated.voice;
|
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.provider.Settings;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility for retrieving settings from Settings.Secure.
|
|
||||||
*/
|
|
||||||
public class SettingsUtil {
|
|
||||||
/**
|
|
||||||
* A whitespace-separated list of supported locales for voice input from the keyboard.
|
|
||||||
*/
|
|
||||||
public static final String LATIN_IME_VOICE_INPUT_SUPPORTED_LOCALES =
|
|
||||||
"latin_ime_voice_input_supported_locales";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A whitespace-separated list of recommended app packages for voice input from the
|
|
||||||
* keyboard.
|
|
||||||
*/
|
|
||||||
public static final String LATIN_IME_VOICE_INPUT_RECOMMENDED_PACKAGES =
|
|
||||||
"latin_ime_voice_input_recommended_packages";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The maximum number of unique days to show the swipe hint for voice input.
|
|
||||||
*/
|
|
||||||
public static final String LATIN_IME_VOICE_INPUT_SWIPE_HINT_MAX_DAYS =
|
|
||||||
"latin_ime_voice_input_swipe_hint_max_days";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The maximum number of times to show the punctuation hint for voice input.
|
|
||||||
*/
|
|
||||||
public static final String LATIN_IME_VOICE_INPUT_PUNCTUATION_HINT_MAX_DISPLAYS =
|
|
||||||
"latin_ime_voice_input_punctuation_hint_max_displays";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Endpointer parameters for voice input from the keyboard.
|
|
||||||
*/
|
|
||||||
public static final String LATIN_IME_SPEECH_MINIMUM_LENGTH_MILLIS =
|
|
||||||
"latin_ime_speech_minimum_length_millis";
|
|
||||||
public static final String LATIN_IME_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS =
|
|
||||||
"latin_ime_speech_input_complete_silence_length_millis";
|
|
||||||
public static final String LATIN_IME_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS =
|
|
||||||
"latin_ime_speech_input_possibly_complete_silence_length_millis";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Min and max volume levels that can be displayed on the "speak now" screen.
|
|
||||||
*/
|
|
||||||
public static final String LATIN_IME_MIN_MICROPHONE_LEVEL =
|
|
||||||
"latin_ime_min_microphone_level";
|
|
||||||
public static final String LATIN_IME_MAX_MICROPHONE_LEVEL =
|
|
||||||
"latin_ime_max_microphone_level";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The number of sentence-level alternates to request of the server.
|
|
||||||
*/
|
|
||||||
public static final String LATIN_IME_MAX_VOICE_RESULTS = "latin_ime_max_voice_results";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a string-valued setting.
|
|
||||||
*
|
|
||||||
* @param cr The content resolver to use
|
|
||||||
* @param key The setting to look up
|
|
||||||
* @param defaultValue The default value to use if none can be found
|
|
||||||
* @return The value of the setting, or defaultValue if it couldn't be found
|
|
||||||
*/
|
|
||||||
public static String getSettingsString(ContentResolver cr, String key, String defaultValue) {
|
|
||||||
String result = Settings.Secure.getString(cr, key);
|
|
||||||
return (result == null) ? defaultValue : result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an int-valued setting.
|
|
||||||
*
|
|
||||||
* @param cr The content resolver to use
|
|
||||||
* @param key The setting to look up
|
|
||||||
* @param defaultValue The default value to use if the setting couldn't be found or parsed
|
|
||||||
* @return The value of the setting, or defaultValue if it couldn't be found or parsed
|
|
||||||
*/
|
|
||||||
public static int getSettingsInt(ContentResolver cr, String key, int defaultValue) {
|
|
||||||
return Settings.Secure.getInt(cr, key, defaultValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a float-valued setting.
|
|
||||||
*
|
|
||||||
* @param cr The content resolver to use
|
|
||||||
* @param key The setting to look up
|
|
||||||
* @param defaultValue The default value to use if the setting couldn't be found or parsed
|
|
||||||
* @return The value of the setting, or defaultValue if it couldn't be found or parsed
|
|
||||||
*/
|
|
||||||
public static float getSettingsFloat(ContentResolver cr, String key, float defaultValue) {
|
|
||||||
return Settings.Secure.getFloat(cr, key, defaultValue);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,155 +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.inputmethod.deprecated.voice;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.Bitmap.Config;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.graphics.PorterDuff;
|
|
||||||
import android.graphics.PorterDuffXfermode;
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
|
|
||||||
import com.android.inputmethod.latin.R;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A widget which shows the volume of audio using a microphone icon
|
|
||||||
*/
|
|
||||||
public class SoundIndicator extends ImageView {
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private static final String TAG = "SoundIndicator";
|
|
||||||
|
|
||||||
private static final float UP_SMOOTHING_FACTOR = 0.9f;
|
|
||||||
private static final float DOWN_SMOOTHING_FACTOR = 0.4f;
|
|
||||||
|
|
||||||
private static final float AUDIO_METER_MIN_DB = 7.0f;
|
|
||||||
private static final float AUDIO_METER_DB_RANGE = 20.0f;
|
|
||||||
|
|
||||||
private static final long FRAME_DELAY = 50;
|
|
||||||
|
|
||||||
private Bitmap mDrawingBuffer;
|
|
||||||
private Canvas mBufferCanvas;
|
|
||||||
private Bitmap mEdgeBitmap;
|
|
||||||
private float mLevel = 0.0f;
|
|
||||||
private Drawable mFrontDrawable;
|
|
||||||
private Paint mClearPaint;
|
|
||||||
private Paint mMultPaint;
|
|
||||||
private int mEdgeBitmapOffset;
|
|
||||||
|
|
||||||
private Handler mHandler;
|
|
||||||
|
|
||||||
private Runnable mDrawFrame = new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
invalidate();
|
|
||||||
mHandler.postDelayed(mDrawFrame, FRAME_DELAY);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public SoundIndicator(Context context) {
|
|
||||||
this(context, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SoundIndicator(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
|
|
||||||
mFrontDrawable = getDrawable();
|
|
||||||
BitmapDrawable edgeDrawable =
|
|
||||||
(BitmapDrawable) context.getResources().getDrawable(R.drawable.vs_popup_mic_edge);
|
|
||||||
mEdgeBitmap = edgeDrawable.getBitmap();
|
|
||||||
mEdgeBitmapOffset = mEdgeBitmap.getHeight() / 2;
|
|
||||||
|
|
||||||
mDrawingBuffer =
|
|
||||||
Bitmap.createBitmap(mFrontDrawable.getIntrinsicWidth(),
|
|
||||||
mFrontDrawable.getIntrinsicHeight(), Config.ARGB_8888);
|
|
||||||
|
|
||||||
mBufferCanvas = new Canvas(mDrawingBuffer);
|
|
||||||
|
|
||||||
// Initialize Paints.
|
|
||||||
mClearPaint = new Paint();
|
|
||||||
mClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
|
|
||||||
|
|
||||||
mMultPaint = new Paint();
|
|
||||||
mMultPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
|
|
||||||
|
|
||||||
mHandler = new Handler();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDraw(Canvas canvas) {
|
|
||||||
//super.onDraw(canvas);
|
|
||||||
|
|
||||||
float w = getWidth();
|
|
||||||
float h = getHeight();
|
|
||||||
|
|
||||||
// Clear the buffer canvas
|
|
||||||
mBufferCanvas.drawRect(0, 0, w, h, mClearPaint);
|
|
||||||
|
|
||||||
// Set its clip so we don't draw the front image all the way to the top
|
|
||||||
Rect clip = new Rect(0,
|
|
||||||
(int) ((1.0 - mLevel) * (h + mEdgeBitmapOffset)) - mEdgeBitmapOffset,
|
|
||||||
(int) w,
|
|
||||||
(int) h);
|
|
||||||
|
|
||||||
mBufferCanvas.save();
|
|
||||||
mBufferCanvas.clipRect(clip);
|
|
||||||
|
|
||||||
// Draw the front image
|
|
||||||
mFrontDrawable.setBounds(new Rect(0, 0, (int) w, (int) h));
|
|
||||||
mFrontDrawable.draw(mBufferCanvas);
|
|
||||||
|
|
||||||
mBufferCanvas.restore();
|
|
||||||
|
|
||||||
// Draw the edge image on top of the buffer image with a multiply mode
|
|
||||||
mBufferCanvas.drawBitmap(mEdgeBitmap, 0, clip.top, mMultPaint);
|
|
||||||
|
|
||||||
// Draw the buffer image (on top of the background image)
|
|
||||||
canvas.drawBitmap(mDrawingBuffer, 0, 0, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the sound level
|
|
||||||
*
|
|
||||||
* @param rmsdB The level of the sound, in dB.
|
|
||||||
*/
|
|
||||||
public void setRmsdB(float rmsdB) {
|
|
||||||
float level = ((rmsdB - AUDIO_METER_MIN_DB) / AUDIO_METER_DB_RANGE);
|
|
||||||
|
|
||||||
level = Math.min(Math.max(0.0f, level), 1.0f);
|
|
||||||
|
|
||||||
// We smooth towards the new level
|
|
||||||
if (level > mLevel) {
|
|
||||||
mLevel = (level - mLevel) * UP_SMOOTHING_FACTOR + mLevel;
|
|
||||||
} else {
|
|
||||||
mLevel = (level - mLevel) * DOWN_SMOOTHING_FACTOR + mLevel;
|
|
||||||
}
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start() {
|
|
||||||
mHandler.post(mDrawFrame);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
mHandler.removeCallbacks(mDrawFrame);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,692 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2009 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.deprecated.voice;
|
|
||||||
|
|
||||||
import com.android.inputmethod.latin.EditingUtils;
|
|
||||||
import com.android.inputmethod.latin.LatinImeLogger;
|
|
||||||
import com.android.inputmethod.latin.R;
|
|
||||||
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
|
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.os.Parcelable;
|
|
||||||
import android.speech.RecognitionListener;
|
|
||||||
import android.speech.RecognizerIntent;
|
|
||||||
import android.speech.SpeechRecognizer;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
import android.view.inputmethod.InputConnection;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Speech recognition input, including both user interface and a background
|
|
||||||
* process to stream audio to the network recognizer. This class supplies a
|
|
||||||
* View (getView()), which it updates as recognition occurs. The user of this
|
|
||||||
* class is responsible for making the view visible to the user, as well as
|
|
||||||
* handling various events returned through UiListener.
|
|
||||||
*/
|
|
||||||
public class VoiceInput implements OnClickListener {
|
|
||||||
private static final String TAG = "VoiceInput";
|
|
||||||
private static final String EXTRA_RECOGNITION_CONTEXT =
|
|
||||||
"android.speech.extras.RECOGNITION_CONTEXT";
|
|
||||||
private static final String EXTRA_CALLING_PACKAGE = "calling_package";
|
|
||||||
private static final String EXTRA_ALTERNATES = "android.speech.extra.ALTERNATES";
|
|
||||||
private static final int MAX_ALT_LIST_LENGTH = 6;
|
|
||||||
private static boolean DBG = LatinImeLogger.sDBG;
|
|
||||||
|
|
||||||
private static final String DEFAULT_RECOMMENDED_PACKAGES =
|
|
||||||
"com.android.mms " +
|
|
||||||
"com.google.android.gm " +
|
|
||||||
"com.google.android.talk " +
|
|
||||||
"com.google.android.apps.googlevoice " +
|
|
||||||
"com.android.email " +
|
|
||||||
"com.android.browser ";
|
|
||||||
|
|
||||||
// WARNING! Before enabling this, fix the problem with calling getExtractedText() in
|
|
||||||
// landscape view. It causes Extracted text updates to be rejected due to a token mismatch
|
|
||||||
public static boolean ENABLE_WORD_CORRECTIONS = true;
|
|
||||||
|
|
||||||
// Dummy word suggestion which means "delete current word"
|
|
||||||
public static final String DELETE_SYMBOL = " \u00D7 "; // times symbol
|
|
||||||
|
|
||||||
private Whitelist mRecommendedList;
|
|
||||||
private Whitelist mBlacklist;
|
|
||||||
|
|
||||||
private VoiceInputLogger mLogger;
|
|
||||||
|
|
||||||
// Names of a few extras defined in VoiceSearch's RecognitionController
|
|
||||||
// Note, the version of voicesearch that shipped in Froyo returns the raw
|
|
||||||
// RecognitionClientAlternates protocol buffer under the key "alternates",
|
|
||||||
// so a VS market update must be installed on Froyo devices in order to see
|
|
||||||
// alternatives.
|
|
||||||
private static final String ALTERNATES_BUNDLE = "alternates_bundle";
|
|
||||||
|
|
||||||
// This is copied from the VoiceSearch app.
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private static final class AlternatesBundleKeys {
|
|
||||||
public static final String ALTERNATES = "alternates";
|
|
||||||
public static final String CONFIDENCE = "confidence";
|
|
||||||
public static final String LENGTH = "length";
|
|
||||||
public static final String MAX_SPAN_LENGTH = "max_span_length";
|
|
||||||
public static final String SPANS = "spans";
|
|
||||||
public static final String SPAN_KEY_DELIMITER = ":";
|
|
||||||
public static final String START = "start";
|
|
||||||
public static final String TEXT = "text";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Names of a few intent extras defined in VoiceSearch's RecognitionService.
|
|
||||||
// These let us tweak the endpointer parameters.
|
|
||||||
private static final String EXTRA_SPEECH_MINIMUM_LENGTH_MILLIS =
|
|
||||||
"android.speech.extras.SPEECH_INPUT_MINIMUM_LENGTH_MILLIS";
|
|
||||||
private static final String EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS =
|
|
||||||
"android.speech.extras.SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS";
|
|
||||||
private static final String EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS =
|
|
||||||
"android.speech.extras.SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS";
|
|
||||||
|
|
||||||
// The usual endpointer default value for input complete silence length is 0.5 seconds,
|
|
||||||
// but that's used for things like voice search. For dictation-like voice input like this,
|
|
||||||
// we go with a more liberal value of 1 second. This value will only be used if a value
|
|
||||||
// is not provided from Gservices.
|
|
||||||
private static final String INPUT_COMPLETE_SILENCE_LENGTH_DEFAULT_VALUE_MILLIS = "1000";
|
|
||||||
|
|
||||||
// Used to record part of that state for logging purposes.
|
|
||||||
public static final int DEFAULT = 0;
|
|
||||||
public static final int LISTENING = 1;
|
|
||||||
public static final int WORKING = 2;
|
|
||||||
public static final int ERROR = 3;
|
|
||||||
|
|
||||||
private int mAfterVoiceInputDeleteCount = 0;
|
|
||||||
private int mAfterVoiceInputInsertCount = 0;
|
|
||||||
private int mAfterVoiceInputInsertPunctuationCount = 0;
|
|
||||||
private int mAfterVoiceInputCursorPos = 0;
|
|
||||||
private int mAfterVoiceInputSelectionSpan = 0;
|
|
||||||
|
|
||||||
private int mState = DEFAULT;
|
|
||||||
|
|
||||||
private final static int MSG_RESET = 1;
|
|
||||||
|
|
||||||
private final UIHandler mHandler = new UIHandler(this);
|
|
||||||
|
|
||||||
private static class UIHandler extends StaticInnerHandlerWrapper<VoiceInput> {
|
|
||||||
public UIHandler(VoiceInput outerInstance) {
|
|
||||||
super(outerInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message msg) {
|
|
||||||
if (msg.what == MSG_RESET) {
|
|
||||||
final VoiceInput voiceInput = getOuterInstance();
|
|
||||||
voiceInput.mState = DEFAULT;
|
|
||||||
voiceInput.mRecognitionView.finish();
|
|
||||||
voiceInput.mUiListener.onCancelVoice();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Events relating to the recognition UI. You must implement these.
|
|
||||||
*/
|
|
||||||
public interface UiListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param recognitionResults a set of transcripts for what the user
|
|
||||||
* spoke, sorted by likelihood.
|
|
||||||
*/
|
|
||||||
public void onVoiceResults(
|
|
||||||
List<String> recognitionResults,
|
|
||||||
Map<String, List<CharSequence>> alternatives);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the user cancels speech recognition.
|
|
||||||
*/
|
|
||||||
public void onCancelVoice();
|
|
||||||
}
|
|
||||||
|
|
||||||
private SpeechRecognizer mSpeechRecognizer;
|
|
||||||
private RecognitionListener mRecognitionListener;
|
|
||||||
private RecognitionView mRecognitionView;
|
|
||||||
private UiListener mUiListener;
|
|
||||||
private Context mContext;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param context the service or activity in which we're running.
|
|
||||||
* @param uiHandler object to receive events from VoiceInput.
|
|
||||||
*/
|
|
||||||
public VoiceInput(Context context, UiListener uiHandler) {
|
|
||||||
mLogger = VoiceInputLogger.getLogger(context);
|
|
||||||
mRecognitionListener = new ImeRecognitionListener();
|
|
||||||
mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(context);
|
|
||||||
mSpeechRecognizer.setRecognitionListener(mRecognitionListener);
|
|
||||||
mUiListener = uiHandler;
|
|
||||||
mContext = context;
|
|
||||||
newView();
|
|
||||||
|
|
||||||
String recommendedPackages = SettingsUtil.getSettingsString(
|
|
||||||
context.getContentResolver(),
|
|
||||||
SettingsUtil.LATIN_IME_VOICE_INPUT_RECOMMENDED_PACKAGES,
|
|
||||||
DEFAULT_RECOMMENDED_PACKAGES);
|
|
||||||
|
|
||||||
mRecommendedList = new Whitelist();
|
|
||||||
for (String recommendedPackage : recommendedPackages.split("\\s+")) {
|
|
||||||
mRecommendedList.addApp(recommendedPackage);
|
|
||||||
}
|
|
||||||
|
|
||||||
mBlacklist = new Whitelist();
|
|
||||||
mBlacklist.addApp("com.google.android.setupwizard");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCursorPos(int pos) {
|
|
||||||
mAfterVoiceInputCursorPos = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCursorPos() {
|
|
||||||
return mAfterVoiceInputCursorPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSelectionSpan(int span) {
|
|
||||||
mAfterVoiceInputSelectionSpan = span;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSelectionSpan() {
|
|
||||||
return mAfterVoiceInputSelectionSpan;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void incrementTextModificationDeleteCount(int count){
|
|
||||||
mAfterVoiceInputDeleteCount += count;
|
|
||||||
// Send up intents for other text modification types
|
|
||||||
if (mAfterVoiceInputInsertCount > 0) {
|
|
||||||
logTextModifiedByTypingInsertion(mAfterVoiceInputInsertCount);
|
|
||||||
mAfterVoiceInputInsertCount = 0;
|
|
||||||
}
|
|
||||||
if (mAfterVoiceInputInsertPunctuationCount > 0) {
|
|
||||||
logTextModifiedByTypingInsertionPunctuation(mAfterVoiceInputInsertPunctuationCount);
|
|
||||||
mAfterVoiceInputInsertPunctuationCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void incrementTextModificationInsertCount(int count){
|
|
||||||
mAfterVoiceInputInsertCount += count;
|
|
||||||
if (mAfterVoiceInputSelectionSpan > 0) {
|
|
||||||
// If text was highlighted before inserting the char, count this as
|
|
||||||
// a delete.
|
|
||||||
mAfterVoiceInputDeleteCount += mAfterVoiceInputSelectionSpan;
|
|
||||||
}
|
|
||||||
// Send up intents for other text modification types
|
|
||||||
if (mAfterVoiceInputDeleteCount > 0) {
|
|
||||||
logTextModifiedByTypingDeletion(mAfterVoiceInputDeleteCount);
|
|
||||||
mAfterVoiceInputDeleteCount = 0;
|
|
||||||
}
|
|
||||||
if (mAfterVoiceInputInsertPunctuationCount > 0) {
|
|
||||||
logTextModifiedByTypingInsertionPunctuation(mAfterVoiceInputInsertPunctuationCount);
|
|
||||||
mAfterVoiceInputInsertPunctuationCount = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void incrementTextModificationInsertPunctuationCount(int count){
|
|
||||||
mAfterVoiceInputInsertPunctuationCount += count;
|
|
||||||
if (mAfterVoiceInputSelectionSpan > 0) {
|
|
||||||
// If text was highlighted before inserting the char, count this as
|
|
||||||
// a delete.
|
|
||||||
mAfterVoiceInputDeleteCount += mAfterVoiceInputSelectionSpan;
|
|
||||||
}
|
|
||||||
// Send up intents for aggregated non-punctuation insertions
|
|
||||||
if (mAfterVoiceInputDeleteCount > 0) {
|
|
||||||
logTextModifiedByTypingDeletion(mAfterVoiceInputDeleteCount);
|
|
||||||
mAfterVoiceInputDeleteCount = 0;
|
|
||||||
}
|
|
||||||
if (mAfterVoiceInputInsertCount > 0) {
|
|
||||||
logTextModifiedByTypingInsertion(mAfterVoiceInputInsertCount);
|
|
||||||
mAfterVoiceInputInsertCount = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void flushAllTextModificationCounters() {
|
|
||||||
if (mAfterVoiceInputInsertCount > 0) {
|
|
||||||
logTextModifiedByTypingInsertion(mAfterVoiceInputInsertCount);
|
|
||||||
mAfterVoiceInputInsertCount = 0;
|
|
||||||
}
|
|
||||||
if (mAfterVoiceInputDeleteCount > 0) {
|
|
||||||
logTextModifiedByTypingDeletion(mAfterVoiceInputDeleteCount);
|
|
||||||
mAfterVoiceInputDeleteCount = 0;
|
|
||||||
}
|
|
||||||
if (mAfterVoiceInputInsertPunctuationCount > 0) {
|
|
||||||
logTextModifiedByTypingInsertionPunctuation(mAfterVoiceInputInsertPunctuationCount);
|
|
||||||
mAfterVoiceInputInsertPunctuationCount = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The configuration of the IME changed and may have caused the views to be layed out
|
|
||||||
* again. Restore the state of the recognition view.
|
|
||||||
*/
|
|
||||||
public void onConfigurationChanged(Configuration configuration) {
|
|
||||||
mRecognitionView.restoreState();
|
|
||||||
mRecognitionView.getView().dispatchConfigurationChanged(configuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if field is blacklisted for voice
|
|
||||||
*/
|
|
||||||
public boolean isBlacklistedField(FieldContext context) {
|
|
||||||
return mBlacklist.matches(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to decide whether to show voice input hints for this field, etc.
|
|
||||||
*
|
|
||||||
* @return true if field is recommended for voice
|
|
||||||
*/
|
|
||||||
public boolean isRecommendedField(FieldContext context) {
|
|
||||||
return mRecommendedList.matches(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start listening for speech from the user. This will grab the microphone
|
|
||||||
* and start updating the view provided by getView(). It is the caller's
|
|
||||||
* responsibility to ensure that the view is visible to the user at this stage.
|
|
||||||
*
|
|
||||||
* @param context the same FieldContext supplied to voiceIsEnabled()
|
|
||||||
* @param swipe whether this voice input was started by swipe, for logging purposes
|
|
||||||
*/
|
|
||||||
public void startListening(FieldContext context, boolean swipe) {
|
|
||||||
if (DBG) {
|
|
||||||
Log.d(TAG, "startListening: " + context);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mState != DEFAULT) {
|
|
||||||
Log.w(TAG, "startListening in the wrong status " + mState);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If everything works ok, the voice input should be already in the correct state. As this
|
|
||||||
// class can be called by third-party, we call reset just to be on the safe side.
|
|
||||||
reset();
|
|
||||||
|
|
||||||
Locale locale = Locale.getDefault();
|
|
||||||
String localeString = locale.getLanguage() + "-" + locale.getCountry();
|
|
||||||
|
|
||||||
mLogger.start(localeString, swipe);
|
|
||||||
|
|
||||||
mState = LISTENING;
|
|
||||||
|
|
||||||
mRecognitionView.showInitializing();
|
|
||||||
startListeningAfterInitialization(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called only when the recognition manager's initialization completed
|
|
||||||
*
|
|
||||||
* @param context context with which {@link #startListening(FieldContext, boolean)} was executed
|
|
||||||
*/
|
|
||||||
private void startListeningAfterInitialization(FieldContext context) {
|
|
||||||
Intent intent = makeIntent();
|
|
||||||
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, "");
|
|
||||||
intent.putExtra(EXTRA_RECOGNITION_CONTEXT, context.getBundle());
|
|
||||||
intent.putExtra(EXTRA_CALLING_PACKAGE, "VoiceIME");
|
|
||||||
intent.putExtra(EXTRA_ALTERNATES, true);
|
|
||||||
intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS,
|
|
||||||
SettingsUtil.getSettingsInt(
|
|
||||||
mContext.getContentResolver(),
|
|
||||||
SettingsUtil.LATIN_IME_MAX_VOICE_RESULTS,
|
|
||||||
1));
|
|
||||||
// Get endpointer params from Gservices.
|
|
||||||
// TODO: Consider caching these values for improved performance on slower devices.
|
|
||||||
final ContentResolver cr = mContext.getContentResolver();
|
|
||||||
putEndpointerExtra(
|
|
||||||
cr,
|
|
||||||
intent,
|
|
||||||
SettingsUtil.LATIN_IME_SPEECH_MINIMUM_LENGTH_MILLIS,
|
|
||||||
EXTRA_SPEECH_MINIMUM_LENGTH_MILLIS,
|
|
||||||
null /* rely on endpointer default */);
|
|
||||||
putEndpointerExtra(
|
|
||||||
cr,
|
|
||||||
intent,
|
|
||||||
SettingsUtil.LATIN_IME_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS,
|
|
||||||
EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS,
|
|
||||||
INPUT_COMPLETE_SILENCE_LENGTH_DEFAULT_VALUE_MILLIS
|
|
||||||
/* our default value is different from the endpointer's */);
|
|
||||||
putEndpointerExtra(
|
|
||||||
cr,
|
|
||||||
intent,
|
|
||||||
SettingsUtil.
|
|
||||||
LATIN_IME_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS,
|
|
||||||
EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS,
|
|
||||||
null /* rely on endpointer default */);
|
|
||||||
|
|
||||||
mSpeechRecognizer.startListening(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the value of the provided Gservices key, attempts to parse it into a long,
|
|
||||||
* and if successful, puts the long value as an extra in the provided intent.
|
|
||||||
*/
|
|
||||||
private void putEndpointerExtra(ContentResolver cr, Intent i,
|
|
||||||
String gservicesKey, String intentExtraKey, String defaultValue) {
|
|
||||||
long l = -1;
|
|
||||||
String s = SettingsUtil.getSettingsString(cr, gservicesKey, defaultValue);
|
|
||||||
if (s != null) {
|
|
||||||
try {
|
|
||||||
l = Long.valueOf(s);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
Log.e(TAG, "could not parse value for " + gservicesKey + ": " + s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (l != -1) i.putExtra(intentExtraKey, l);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void destroy() {
|
|
||||||
mSpeechRecognizer.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new instance of the view that is returned by {@link #getView()}
|
|
||||||
* Clients should use this when a previously returned view is stuck in a
|
|
||||||
* layout that is being thrown away and a new one is need to show to the
|
|
||||||
* user.
|
|
||||||
*/
|
|
||||||
public void newView() {
|
|
||||||
mRecognitionView = new RecognitionView(mContext, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return a view that shows the recognition flow--e.g., "Speak now" and
|
|
||||||
* "working" dialogs.
|
|
||||||
*/
|
|
||||||
public View getView() {
|
|
||||||
return mRecognitionView.getView();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the cancel button.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
switch(view.getId()) {
|
|
||||||
case R.id.button:
|
|
||||||
cancel();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void logTextModifiedByTypingInsertion(int length) {
|
|
||||||
mLogger.textModifiedByTypingInsertion(length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void logTextModifiedByTypingInsertionPunctuation(int length) {
|
|
||||||
mLogger.textModifiedByTypingInsertionPunctuation(length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void logTextModifiedByTypingDeletion(int length) {
|
|
||||||
mLogger.textModifiedByTypingDeletion(length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void logTextModifiedByChooseSuggestion(String suggestion, int index,
|
|
||||||
String wordSeparators, InputConnection ic) {
|
|
||||||
String wordToBeReplaced = EditingUtils.getWordAtCursor(ic, wordSeparators);
|
|
||||||
// If we enable phrase-based alternatives, only send up the first word
|
|
||||||
// in suggestion and wordToBeReplaced.
|
|
||||||
mLogger.textModifiedByChooseSuggestion(suggestion.length(), wordToBeReplaced.length(),
|
|
||||||
index, wordToBeReplaced, suggestion);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void logKeyboardWarningDialogShown() {
|
|
||||||
mLogger.keyboardWarningDialogShown();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void logKeyboardWarningDialogDismissed() {
|
|
||||||
mLogger.keyboardWarningDialogDismissed();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void logKeyboardWarningDialogOk() {
|
|
||||||
mLogger.keyboardWarningDialogOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void logKeyboardWarningDialogCancel() {
|
|
||||||
mLogger.keyboardWarningDialogCancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void logSwipeHintDisplayed() {
|
|
||||||
mLogger.swipeHintDisplayed();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void logPunctuationHintDisplayed() {
|
|
||||||
mLogger.punctuationHintDisplayed();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void logVoiceInputDelivered(int length) {
|
|
||||||
mLogger.voiceInputDelivered(length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void logInputEnded() {
|
|
||||||
mLogger.inputEnded();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void flushLogs() {
|
|
||||||
mLogger.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Intent makeIntent() {
|
|
||||||
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
|
|
||||||
|
|
||||||
// On Cupcake, use VoiceIMEHelper since VoiceSearch doesn't support.
|
|
||||||
// On Donut, always use VoiceSearch, since VoiceIMEHelper and
|
|
||||||
// VoiceSearch may conflict.
|
|
||||||
if (Build.VERSION.RELEASE.equals("1.5")) {
|
|
||||||
intent = intent.setClassName(
|
|
||||||
"com.google.android.voiceservice",
|
|
||||||
"com.google.android.voiceservice.IMERecognitionService");
|
|
||||||
} else {
|
|
||||||
intent = intent.setClassName(
|
|
||||||
"com.google.android.voicesearch",
|
|
||||||
"com.google.android.voicesearch.RecognitionService");
|
|
||||||
}
|
|
||||||
|
|
||||||
return intent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the current voice recognition.
|
|
||||||
*/
|
|
||||||
public void reset() {
|
|
||||||
if (mState != DEFAULT) {
|
|
||||||
mState = DEFAULT;
|
|
||||||
|
|
||||||
// Remove all pending tasks (e.g., timers to cancel voice input)
|
|
||||||
mHandler.removeMessages(MSG_RESET);
|
|
||||||
|
|
||||||
mSpeechRecognizer.cancel();
|
|
||||||
mRecognitionView.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancel in-progress speech recognition.
|
|
||||||
*/
|
|
||||||
public void cancel() {
|
|
||||||
switch (mState) {
|
|
||||||
case LISTENING:
|
|
||||||
mLogger.cancelDuringListening();
|
|
||||||
break;
|
|
||||||
case WORKING:
|
|
||||||
mLogger.cancelDuringWorking();
|
|
||||||
break;
|
|
||||||
case ERROR:
|
|
||||||
mLogger.cancelDuringError();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
reset();
|
|
||||||
mUiListener.onCancelVoice();
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getErrorStringId(int errorType, boolean endpointed) {
|
|
||||||
switch (errorType) {
|
|
||||||
// We use CLIENT_ERROR to signify that voice search is not available on the device.
|
|
||||||
case SpeechRecognizer.ERROR_CLIENT:
|
|
||||||
return R.string.voice_not_installed;
|
|
||||||
case SpeechRecognizer.ERROR_NETWORK:
|
|
||||||
return R.string.voice_network_error;
|
|
||||||
case SpeechRecognizer.ERROR_NETWORK_TIMEOUT:
|
|
||||||
return endpointed ?
|
|
||||||
R.string.voice_network_error : R.string.voice_too_much_speech;
|
|
||||||
case SpeechRecognizer.ERROR_AUDIO:
|
|
||||||
return R.string.voice_audio_error;
|
|
||||||
case SpeechRecognizer.ERROR_SERVER:
|
|
||||||
return R.string.voice_server_error;
|
|
||||||
case SpeechRecognizer.ERROR_SPEECH_TIMEOUT:
|
|
||||||
return R.string.voice_speech_timeout;
|
|
||||||
case SpeechRecognizer.ERROR_NO_MATCH:
|
|
||||||
return R.string.voice_no_match;
|
|
||||||
default: return R.string.voice_error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onError(int errorType, boolean endpointed) {
|
|
||||||
Log.i(TAG, "error " + errorType);
|
|
||||||
mLogger.error(errorType);
|
|
||||||
onError(mContext.getString(getErrorStringId(errorType, endpointed)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onError(String error) {
|
|
||||||
mState = ERROR;
|
|
||||||
mRecognitionView.showError(error);
|
|
||||||
// Wait a couple seconds and then automatically dismiss message.
|
|
||||||
mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_RESET), 2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ImeRecognitionListener implements RecognitionListener {
|
|
||||||
// Waveform data
|
|
||||||
final ByteArrayOutputStream mWaveBuffer = new ByteArrayOutputStream();
|
|
||||||
int mSpeechStart;
|
|
||||||
private boolean mEndpointed = false;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReadyForSpeech(Bundle noiseParams) {
|
|
||||||
mRecognitionView.showListening();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBeginningOfSpeech() {
|
|
||||||
mEndpointed = false;
|
|
||||||
mSpeechStart = mWaveBuffer.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRmsChanged(float rmsdB) {
|
|
||||||
mRecognitionView.updateVoiceMeter(rmsdB);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBufferReceived(byte[] buf) {
|
|
||||||
try {
|
|
||||||
mWaveBuffer.write(buf);
|
|
||||||
} catch (IOException e) {
|
|
||||||
// ignore.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEndOfSpeech() {
|
|
||||||
mEndpointed = true;
|
|
||||||
mState = WORKING;
|
|
||||||
mRecognitionView.showWorking(mWaveBuffer, mSpeechStart, mWaveBuffer.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(int errorType) {
|
|
||||||
mState = ERROR;
|
|
||||||
VoiceInput.this.onError(errorType, mEndpointed);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResults(Bundle resultsBundle) {
|
|
||||||
List<String> results = resultsBundle
|
|
||||||
.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
|
|
||||||
// VS Market update is needed for IME froyo clients to access the alternatesBundle
|
|
||||||
// TODO: verify this.
|
|
||||||
Bundle alternatesBundle = resultsBundle.getBundle(ALTERNATES_BUNDLE);
|
|
||||||
mState = DEFAULT;
|
|
||||||
|
|
||||||
final Map<String, List<CharSequence>> alternatives =
|
|
||||||
new HashMap<String, List<CharSequence>>();
|
|
||||||
|
|
||||||
if (ENABLE_WORD_CORRECTIONS && alternatesBundle != null && results.size() > 0) {
|
|
||||||
// Use the top recognition result to map each alternative's start:length to a word.
|
|
||||||
String[] words = results.get(0).split(" ");
|
|
||||||
Bundle spansBundle = alternatesBundle.getBundle(AlternatesBundleKeys.SPANS);
|
|
||||||
for (String key : spansBundle.keySet()) {
|
|
||||||
// Get the word for which these alternates correspond to.
|
|
||||||
Bundle spanBundle = spansBundle.getBundle(key);
|
|
||||||
int start = spanBundle.getInt(AlternatesBundleKeys.START);
|
|
||||||
int length = spanBundle.getInt(AlternatesBundleKeys.LENGTH);
|
|
||||||
// Only keep single-word based alternatives.
|
|
||||||
if (length == 1 && start < words.length) {
|
|
||||||
// Get the alternatives associated with the span.
|
|
||||||
// If a word appears twice in a recognition result,
|
|
||||||
// concatenate the alternatives for the word.
|
|
||||||
List<CharSequence> altList = alternatives.get(words[start]);
|
|
||||||
if (altList == null) {
|
|
||||||
altList = new ArrayList<CharSequence>();
|
|
||||||
alternatives.put(words[start], altList);
|
|
||||||
}
|
|
||||||
Parcelable[] alternatesArr = spanBundle
|
|
||||||
.getParcelableArray(AlternatesBundleKeys.ALTERNATES);
|
|
||||||
for (int j = 0; j < alternatesArr.length &&
|
|
||||||
altList.size() < MAX_ALT_LIST_LENGTH; j++) {
|
|
||||||
Bundle alternateBundle = (Bundle) alternatesArr[j];
|
|
||||||
String alternate = alternateBundle.getString(AlternatesBundleKeys.TEXT);
|
|
||||||
// Don't allow duplicates in the alternates list.
|
|
||||||
if (!altList.contains(alternate)) {
|
|
||||||
altList.add(alternate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (results.size() > 5) {
|
|
||||||
results = results.subList(0, 5);
|
|
||||||
}
|
|
||||||
mUiListener.onVoiceResults(results, alternatives);
|
|
||||||
mRecognitionView.finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPartialResults(final Bundle partialResults) {
|
|
||||||
// currently - do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEvent(int eventType, Bundle params) {
|
|
||||||
// do nothing - reserved for events that might be added in the future
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,266 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2008 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.inputmethod.deprecated.voice;
|
|
||||||
|
|
||||||
import com.android.common.speech.LoggingEvents;
|
|
||||||
import com.android.inputmethod.deprecated.compat.VoiceInputLoggerCompatUtils;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides the logging facility for voice input events. This fires broadcasts back to
|
|
||||||
* the voice search app which then logs on our behalf.
|
|
||||||
*
|
|
||||||
* Note that debug console logging does not occur in this class. If you want to
|
|
||||||
* see console output of these logging events, there is a boolean switch to turn
|
|
||||||
* on on the VoiceSearch side.
|
|
||||||
*/
|
|
||||||
public class VoiceInputLogger {
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private static final String TAG = VoiceInputLogger.class.getSimpleName();
|
|
||||||
|
|
||||||
private static VoiceInputLogger sVoiceInputLogger;
|
|
||||||
|
|
||||||
private final Context mContext;
|
|
||||||
|
|
||||||
// The base intent used to form all broadcast intents to the logger
|
|
||||||
// in VoiceSearch.
|
|
||||||
private final Intent mBaseIntent;
|
|
||||||
|
|
||||||
// This flag is used to indicate when there are voice events that
|
|
||||||
// need to be flushed.
|
|
||||||
private boolean mHasLoggingInfo = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the singleton of the logger.
|
|
||||||
*
|
|
||||||
* @param contextHint a hint context used when creating the logger instance.
|
|
||||||
* Ignored if the singleton instance already exists.
|
|
||||||
*/
|
|
||||||
public static synchronized VoiceInputLogger getLogger(Context contextHint) {
|
|
||||||
if (sVoiceInputLogger == null) {
|
|
||||||
sVoiceInputLogger = new VoiceInputLogger(contextHint);
|
|
||||||
}
|
|
||||||
return sVoiceInputLogger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public VoiceInputLogger(Context context) {
|
|
||||||
mContext = context;
|
|
||||||
|
|
||||||
mBaseIntent = new Intent(LoggingEvents.ACTION_LOG_EVENT);
|
|
||||||
mBaseIntent.putExtra(LoggingEvents.EXTRA_APP_NAME, LoggingEvents.VoiceIme.APP_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Intent newLoggingBroadcast(int event) {
|
|
||||||
Intent i = new Intent(mBaseIntent);
|
|
||||||
i.putExtra(LoggingEvents.EXTRA_EVENT, event);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void flush() {
|
|
||||||
if (hasLoggingInfo()) {
|
|
||||||
Intent i = new Intent(mBaseIntent);
|
|
||||||
i.putExtra(LoggingEvents.EXTRA_FLUSH, true);
|
|
||||||
mContext.sendBroadcast(i);
|
|
||||||
setHasLoggingInfo(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void keyboardWarningDialogShown() {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
mContext.sendBroadcast(newLoggingBroadcast(
|
|
||||||
LoggingEvents.VoiceIme.KEYBOARD_WARNING_DIALOG_SHOWN));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void keyboardWarningDialogDismissed() {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
mContext.sendBroadcast(newLoggingBroadcast(
|
|
||||||
LoggingEvents.VoiceIme.KEYBOARD_WARNING_DIALOG_DISMISSED));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void keyboardWarningDialogOk() {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
mContext.sendBroadcast(newLoggingBroadcast(
|
|
||||||
LoggingEvents.VoiceIme.KEYBOARD_WARNING_DIALOG_OK));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void keyboardWarningDialogCancel() {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
mContext.sendBroadcast(newLoggingBroadcast(
|
|
||||||
LoggingEvents.VoiceIme.KEYBOARD_WARNING_DIALOG_CANCEL));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void settingsWarningDialogShown() {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
mContext.sendBroadcast(newLoggingBroadcast(
|
|
||||||
LoggingEvents.VoiceIme.SETTINGS_WARNING_DIALOG_SHOWN));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void settingsWarningDialogDismissed() {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
mContext.sendBroadcast(newLoggingBroadcast(
|
|
||||||
LoggingEvents.VoiceIme.SETTINGS_WARNING_DIALOG_DISMISSED));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void settingsWarningDialogOk() {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
mContext.sendBroadcast(newLoggingBroadcast(
|
|
||||||
LoggingEvents.VoiceIme.SETTINGS_WARNING_DIALOG_OK));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void settingsWarningDialogCancel() {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
mContext.sendBroadcast(newLoggingBroadcast(
|
|
||||||
LoggingEvents.VoiceIme.SETTINGS_WARNING_DIALOG_CANCEL));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void swipeHintDisplayed() {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.SWIPE_HINT_DISPLAYED));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cancelDuringListening() {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.CANCEL_DURING_LISTENING));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cancelDuringWorking() {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.CANCEL_DURING_WORKING));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cancelDuringError() {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.CANCEL_DURING_ERROR));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void punctuationHintDisplayed() {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
mContext.sendBroadcast(newLoggingBroadcast(
|
|
||||||
LoggingEvents.VoiceIme.PUNCTUATION_HINT_DISPLAYED));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void error(int code) {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.ERROR);
|
|
||||||
i.putExtra(LoggingEvents.VoiceIme.EXTRA_ERROR_CODE, code);
|
|
||||||
mContext.sendBroadcast(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(String locale, boolean swipe) {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.START);
|
|
||||||
i.putExtra(LoggingEvents.VoiceIme.EXTRA_START_LOCALE, locale);
|
|
||||||
i.putExtra(LoggingEvents.VoiceIme.EXTRA_START_SWIPE, swipe);
|
|
||||||
i.putExtra(LoggingEvents.EXTRA_TIMESTAMP, System.currentTimeMillis());
|
|
||||||
mContext.sendBroadcast(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void voiceInputDelivered(int length) {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.VOICE_INPUT_DELIVERED);
|
|
||||||
i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_LENGTH, length);
|
|
||||||
mContext.sendBroadcast(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void textModifiedByTypingInsertion(int length) {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.TEXT_MODIFIED);
|
|
||||||
i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_LENGTH, length);
|
|
||||||
i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_TYPE,
|
|
||||||
LoggingEvents.VoiceIme.TEXT_MODIFIED_TYPE_TYPING_INSERTION);
|
|
||||||
mContext.sendBroadcast(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void textModifiedByTypingInsertionPunctuation(int length) {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.TEXT_MODIFIED);
|
|
||||||
i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_LENGTH, length);
|
|
||||||
i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_TYPE,
|
|
||||||
LoggingEvents.VoiceIme.TEXT_MODIFIED_TYPE_TYPING_INSERTION_PUNCTUATION);
|
|
||||||
mContext.sendBroadcast(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void textModifiedByTypingDeletion(int length) {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.TEXT_MODIFIED);
|
|
||||||
i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_LENGTH, length);
|
|
||||||
i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_TYPE,
|
|
||||||
LoggingEvents.VoiceIme.TEXT_MODIFIED_TYPE_TYPING_DELETION);
|
|
||||||
|
|
||||||
mContext.sendBroadcast(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void textModifiedByChooseSuggestion(int suggestionLength, int replacedPhraseLength,
|
|
||||||
int index, String before, String after) {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.TEXT_MODIFIED);
|
|
||||||
i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_LENGTH, suggestionLength);
|
|
||||||
i.putExtra(VoiceInputLoggerCompatUtils.EXTRA_TEXT_REPLACED_LENGTH, replacedPhraseLength);
|
|
||||||
i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_TYPE,
|
|
||||||
LoggingEvents.VoiceIme.TEXT_MODIFIED_TYPE_CHOOSE_SUGGESTION);
|
|
||||||
i.putExtra(LoggingEvents.VoiceIme.EXTRA_N_BEST_CHOOSE_INDEX, index);
|
|
||||||
i.putExtra(VoiceInputLoggerCompatUtils.EXTRA_BEFORE_N_BEST_CHOOSE, before);
|
|
||||||
i.putExtra(VoiceInputLoggerCompatUtils.EXTRA_AFTER_N_BEST_CHOOSE, after);
|
|
||||||
mContext.sendBroadcast(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void inputEnded() {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.INPUT_ENDED));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void voiceInputSettingEnabled() {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
mContext.sendBroadcast(newLoggingBroadcast(
|
|
||||||
LoggingEvents.VoiceIme.VOICE_INPUT_SETTING_ENABLED));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void voiceInputSettingDisabled() {
|
|
||||||
setHasLoggingInfo(true);
|
|
||||||
mContext.sendBroadcast(newLoggingBroadcast(
|
|
||||||
LoggingEvents.VoiceIme.VOICE_INPUT_SETTING_DISABLED));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setHasLoggingInfo(boolean hasLoggingInfo) {
|
|
||||||
mHasLoggingInfo = hasLoggingInfo;
|
|
||||||
// If applications that call UserHappinessSignals.userAcceptedImeText
|
|
||||||
// make that call after VoiceInputLogger.flush() calls this method with false, we
|
|
||||||
// will lose those happiness signals. For example, consider the gmail sequence:
|
|
||||||
// 1. compose message
|
|
||||||
// 2. speak message into message field
|
|
||||||
// 3. type subject into subject field
|
|
||||||
// 4. press send
|
|
||||||
// We will NOT get the signal that the user accepted the voice inputted message text
|
|
||||||
// because when the user tapped on the subject field, the ime's flush will be triggered
|
|
||||||
// and the hasLoggingInfo will be then set to false. So by the time the user hits send
|
|
||||||
// we have essentially forgotten about any voice input.
|
|
||||||
// However the following (more common) use case is properly logged
|
|
||||||
// 1. compose message
|
|
||||||
// 2. type subject in subject field
|
|
||||||
// 3. speak message in message field
|
|
||||||
// 4. press send
|
|
||||||
VoiceInputLoggerCompatUtils.setHasVoiceLoggingInfoCompat(hasLoggingInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasLoggingInfo(){
|
|
||||||
return mHasLoggingInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,92 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2008-2009 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.deprecated.voice;
|
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.Paint;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
import java.nio.ShortBuffer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility class to draw a waveform into a bitmap, given a byte array
|
|
||||||
* that represents the waveform as a sequence of 16-bit integers.
|
|
||||||
* Adapted from RecognitionActivity.java.
|
|
||||||
*/
|
|
||||||
public class WaveformImage {
|
|
||||||
private static final int SAMPLING_RATE = 8000;
|
|
||||||
|
|
||||||
private WaveformImage() {
|
|
||||||
// Intentional empty constructor.
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Bitmap drawWaveform(
|
|
||||||
ByteArrayOutputStream waveBuffer, int w, int h, int start, int end) {
|
|
||||||
final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
|
|
||||||
final Canvas c = new Canvas(b);
|
|
||||||
final Paint paint = new Paint();
|
|
||||||
paint.setColor(0xFFFFFFFF); // 0xRRGGBBAA
|
|
||||||
paint.setAntiAlias(true);
|
|
||||||
paint.setStrokeWidth(0);
|
|
||||||
|
|
||||||
final ShortBuffer buf = ByteBuffer
|
|
||||||
.wrap(waveBuffer.toByteArray())
|
|
||||||
.order(ByteOrder.nativeOrder())
|
|
||||||
.asShortBuffer();
|
|
||||||
buf.position(0);
|
|
||||||
|
|
||||||
final int numSamples = waveBuffer.size() / 2;
|
|
||||||
final int delay = (SAMPLING_RATE * 100 / 1000);
|
|
||||||
int endIndex = end / 2 + delay;
|
|
||||||
if (end == 0 || endIndex >= numSamples) {
|
|
||||||
endIndex = numSamples;
|
|
||||||
}
|
|
||||||
int index = start / 2 - delay;
|
|
||||||
if (index < 0) {
|
|
||||||
index = 0;
|
|
||||||
}
|
|
||||||
final int size = endIndex - index;
|
|
||||||
int numSamplePerPixel = 32;
|
|
||||||
int delta = size / (numSamplePerPixel * w);
|
|
||||||
if (delta == 0) {
|
|
||||||
numSamplePerPixel = size / w;
|
|
||||||
delta = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
final float scale = 3.5f / 65536.0f;
|
|
||||||
// do one less column to make sure we won't read past
|
|
||||||
// the buffer.
|
|
||||||
try {
|
|
||||||
for (int i = 0; i < w - 1 ; i++) {
|
|
||||||
final float x = i;
|
|
||||||
for (int j = 0; j < numSamplePerPixel; j++) {
|
|
||||||
final short s = buf.get(index);
|
|
||||||
final float y = (h / 2) - (s * h * scale);
|
|
||||||
c.drawPoint(x, y, paint);
|
|
||||||
index += delta;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IndexOutOfBoundsException e) {
|
|
||||||
// this can happen, but we don't care
|
|
||||||
}
|
|
||||||
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2009 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.deprecated.voice;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A set of text fields where speech has been explicitly enabled.
|
|
||||||
*/
|
|
||||||
public class Whitelist {
|
|
||||||
private List<Bundle> mConditions;
|
|
||||||
|
|
||||||
public Whitelist() {
|
|
||||||
mConditions = new ArrayList<Bundle>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Whitelist(List<Bundle> conditions) {
|
|
||||||
this.mConditions = conditions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addApp(String app) {
|
|
||||||
Bundle bundle = new Bundle();
|
|
||||||
bundle.putString("packageName", app);
|
|
||||||
mConditions.add(bundle);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if the field is a member of the whitelist.
|
|
||||||
*/
|
|
||||||
public boolean matches(FieldContext context) {
|
|
||||||
for (Bundle condition : mConditions) {
|
|
||||||
if (matches(condition, context.getBundle())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true of all values in condition are matched by a value
|
|
||||||
* in target.
|
|
||||||
*/
|
|
||||||
private boolean matches(Bundle condition, Bundle target) {
|
|
||||||
for (String key : condition.keySet()) {
|
|
||||||
if (!condition.getString(key).equals(target.getString(key))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -390,30 +390,4 @@ public class KeyboardSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Should be removed. This is no longer required if {@link InputMethodSubtype} is
|
|
||||||
// supported.
|
|
||||||
public static String parseKeyboardLocale(Resources res, int resId)
|
|
||||||
throws XmlPullParserException, IOException {
|
|
||||||
final XmlPullParser parser = res.getXml(resId);
|
|
||||||
if (parser == null)
|
|
||||||
return "";
|
|
||||||
int event;
|
|
||||||
while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
|
|
||||||
if (event == XmlPullParser.START_TAG) {
|
|
||||||
final String tag = parser.getName();
|
|
||||||
if (TAG_KEYBOARD_SET.equals(tag)) {
|
|
||||||
final TypedArray keyboardSetAttr = res.obtainAttributes(
|
|
||||||
Xml.asAttributeSet(parser), R.styleable.KeyboardSet);
|
|
||||||
final String locale = keyboardSetAttr.getString(
|
|
||||||
R.styleable.KeyboardSet_keyboardLocale);
|
|
||||||
keyboardSetAttr.recycle();
|
|
||||||
return locale;
|
|
||||||
} else {
|
|
||||||
throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD_SET);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,6 @@ import android.widget.PopupWindow;
|
||||||
|
|
||||||
import com.android.inputmethod.accessibility.AccessibilityUtils;
|
import com.android.inputmethod.accessibility.AccessibilityUtils;
|
||||||
import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy;
|
import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy;
|
||||||
import com.android.inputmethod.deprecated.VoiceProxy;
|
|
||||||
import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
|
import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
|
||||||
import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
|
import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
|
||||||
import com.android.inputmethod.keyboard.internal.KeySpecParser;
|
import com.android.inputmethod.keyboard.internal.KeySpecParser;
|
||||||
|
@ -828,12 +827,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onAttachedToWindow() {
|
|
||||||
// Token is available from here.
|
|
||||||
VoiceProxy.getInstance().onAttachedToWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receives hover events from the input framework. This method overrides
|
* Receives hover events from the input framework. This method overrides
|
||||||
* View.dispatchHoverEvent(MotionEvent) on SDK version ICS or higher. On
|
* View.dispatchHoverEvent(MotionEvent) on SDK version ICS or higher. On
|
||||||
|
|
|
@ -60,8 +60,6 @@ import com.android.inputmethod.compat.InputMethodServiceCompatWrapper;
|
||||||
import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper;
|
import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper;
|
||||||
import com.android.inputmethod.compat.InputTypeCompatUtils;
|
import com.android.inputmethod.compat.InputTypeCompatUtils;
|
||||||
import com.android.inputmethod.compat.SuggestionSpanUtils;
|
import com.android.inputmethod.compat.SuggestionSpanUtils;
|
||||||
import com.android.inputmethod.deprecated.LanguageSwitcherProxy;
|
|
||||||
import com.android.inputmethod.deprecated.VoiceProxy;
|
|
||||||
import com.android.inputmethod.keyboard.Keyboard;
|
import com.android.inputmethod.keyboard.Keyboard;
|
||||||
import com.android.inputmethod.keyboard.KeyboardActionListener;
|
import com.android.inputmethod.keyboard.KeyboardActionListener;
|
||||||
import com.android.inputmethod.keyboard.KeyboardId;
|
import com.android.inputmethod.keyboard.KeyboardId;
|
||||||
|
@ -193,7 +191,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
private SharedPreferences mPrefs;
|
private SharedPreferences mPrefs;
|
||||||
/* package for tests */ final KeyboardSwitcher mKeyboardSwitcher;
|
/* package for tests */ final KeyboardSwitcher mKeyboardSwitcher;
|
||||||
private final SubtypeSwitcher mSubtypeSwitcher;
|
private final SubtypeSwitcher mSubtypeSwitcher;
|
||||||
private VoiceProxy mVoiceProxy;
|
|
||||||
private boolean mShouldSwitchToLastSubtype = true;
|
private boolean mShouldSwitchToLastSubtype = true;
|
||||||
|
|
||||||
private UserDictionary mUserDictionary;
|
private UserDictionary mUserDictionary;
|
||||||
|
@ -234,7 +231,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
|
|
||||||
public static class UIHandler extends StaticInnerHandlerWrapper<LatinIME> {
|
public static class UIHandler extends StaticInnerHandlerWrapper<LatinIME> {
|
||||||
private static final int MSG_UPDATE_SHIFT_STATE = 1;
|
private static final int MSG_UPDATE_SHIFT_STATE = 1;
|
||||||
private static final int MSG_VOICE_RESULTS = 2;
|
|
||||||
private static final int MSG_SPACE_TYPED = 4;
|
private static final int MSG_SPACE_TYPED = 4;
|
||||||
private static final int MSG_SET_BIGRAM_PREDICTIONS = 5;
|
private static final int MSG_SET_BIGRAM_PREDICTIONS = 5;
|
||||||
private static final int MSG_PENDING_IMS_CALLBACK = 6;
|
private static final int MSG_PENDING_IMS_CALLBACK = 6;
|
||||||
|
@ -272,11 +268,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
case MSG_SET_BIGRAM_PREDICTIONS:
|
case MSG_SET_BIGRAM_PREDICTIONS:
|
||||||
latinIme.updateBigramPredictions();
|
latinIme.updateBigramPredictions();
|
||||||
break;
|
break;
|
||||||
case MSG_VOICE_RESULTS:
|
|
||||||
final Keyboard keyboard = switcher.getKeyboard();
|
|
||||||
latinIme.mVoiceProxy.handleVoiceResults(latinIme.preferCapitalization()
|
|
||||||
|| (keyboard != null && keyboard.isShiftedOrShiftLocked()));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,10 +302,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
removeMessages(MSG_SET_BIGRAM_PREDICTIONS);
|
removeMessages(MSG_SET_BIGRAM_PREDICTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateVoiceResults() {
|
|
||||||
sendMessage(obtainMessage(MSG_VOICE_RESULTS));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startDoubleSpacesTimer() {
|
public void startDoubleSpacesTimer() {
|
||||||
removeMessages(MSG_SPACE_TYPED);
|
removeMessages(MSG_SPACE_TYPED);
|
||||||
sendMessageDelayed(obtainMessage(MSG_SPACE_TYPED), mDoubleSpacesTurnIntoPeriodTimeout);
|
sendMessageDelayed(obtainMessage(MSG_SPACE_TYPED), mDoubleSpacesTurnIntoPeriodTimeout);
|
||||||
|
@ -436,7 +423,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
if (ProductionFlag.IS_EXPERIMENTAL) {
|
if (ProductionFlag.IS_EXPERIMENTAL) {
|
||||||
ResearchLogger.init(this, prefs);
|
ResearchLogger.init(this, prefs);
|
||||||
}
|
}
|
||||||
LanguageSwitcherProxy.init(this, prefs);
|
|
||||||
InputMethodManagerCompatWrapper.init(this);
|
InputMethodManagerCompatWrapper.init(this);
|
||||||
SubtypeSwitcher.init(this);
|
SubtypeSwitcher.init(this);
|
||||||
KeyboardSwitcher.init(this, prefs);
|
KeyboardSwitcher.init(this, prefs);
|
||||||
|
@ -476,7 +462,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||||
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
|
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
|
||||||
registerReceiver(mReceiver, filter);
|
registerReceiver(mReceiver, filter);
|
||||||
mVoiceProxy = VoiceProxy.init(this, prefs, mHandler);
|
|
||||||
|
|
||||||
final IntentFilter packageFilter = new IntentFilter();
|
final IntentFilter packageFilter = new IntentFilter();
|
||||||
packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
|
packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
|
||||||
|
@ -577,7 +562,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
}
|
}
|
||||||
unregisterReceiver(mReceiver);
|
unregisterReceiver(mReceiver);
|
||||||
unregisterReceiver(mDictionaryPackInstallReceiver);
|
unregisterReceiver(mDictionaryPackInstallReceiver);
|
||||||
mVoiceProxy.destroy();
|
|
||||||
LatinImeLogger.commit();
|
LatinImeLogger.commit();
|
||||||
LatinImeLogger.onDestroy();
|
LatinImeLogger.onDestroy();
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
@ -596,14 +580,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
if (isShowingOptionDialog())
|
if (isShowingOptionDialog())
|
||||||
mOptionsDialog.dismiss();
|
mOptionsDialog.dismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
mVoiceProxy.startChangingConfiguration();
|
|
||||||
super.onConfigurationChanged(conf);
|
super.onConfigurationChanged(conf);
|
||||||
mVoiceProxy.onConfigurationChanged(conf);
|
|
||||||
mVoiceProxy.finishChangingConfiguration();
|
|
||||||
|
|
||||||
// This will work only when the subtype is not supported.
|
|
||||||
LanguageSwitcherProxy.onConfigurationChanged(conf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -698,13 +675,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
|
|
||||||
mSubtypeSwitcher.updateParametersOnStartInputView();
|
mSubtypeSwitcher.updateParametersOnStartInputView();
|
||||||
|
|
||||||
// Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
|
|
||||||
// know now whether this is a password text field, because we need to know now whether we
|
|
||||||
// want to enable the voice button.
|
|
||||||
final int inputType = editorInfo.inputType;
|
|
||||||
mVoiceProxy.resetVoiceStates(InputTypeCompatUtils.isPasswordInputType(inputType)
|
|
||||||
|| InputTypeCompatUtils.isVisiblePasswordInputType(inputType));
|
|
||||||
|
|
||||||
// The EditorInfo might have a flag that affects fullscreen mode.
|
// The EditorInfo might have a flag that affects fullscreen mode.
|
||||||
// Note: This call should be done by InputMethodService?
|
// Note: This call should be done by InputMethodService?
|
||||||
updateFullscreenMode();
|
updateFullscreenMode();
|
||||||
|
@ -726,9 +696,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
if (mSuggest != null && mSettingsValues.mAutoCorrectEnabled) {
|
if (mSuggest != null && mSettingsValues.mAutoCorrectEnabled) {
|
||||||
mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
|
mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
|
||||||
}
|
}
|
||||||
mVoiceProxy.loadSettings(editorInfo, mPrefs);
|
|
||||||
// This will work only when the subtype is not supported.
|
|
||||||
LanguageSwitcherProxy.loadSettings();
|
|
||||||
|
|
||||||
if (mSubtypeSwitcher.isKeyboardMode()) {
|
if (mSubtypeSwitcher.isKeyboardMode()) {
|
||||||
switcher.loadKeyboard(editorInfo, mSettingsValues);
|
switcher.loadKeyboard(editorInfo, mSettingsValues);
|
||||||
|
@ -746,8 +713,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
mSettingsValues.mKeyPreviewPopupDismissDelay);
|
mSettingsValues.mKeyPreviewPopupDismissDelay);
|
||||||
inputView.setProximityCorrectionEnabled(true);
|
inputView.setProximityCorrectionEnabled(true);
|
||||||
|
|
||||||
mVoiceProxy.onStartInputView(inputView.getWindowToken());
|
|
||||||
|
|
||||||
if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
|
if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,8 +728,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
|
|
||||||
LatinImeLogger.commit();
|
LatinImeLogger.commit();
|
||||||
|
|
||||||
mVoiceProxy.flushVoiceInputLogs();
|
|
||||||
|
|
||||||
KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
|
KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
|
||||||
if (inputView != null) inputView.closing();
|
if (inputView != null) inputView.closing();
|
||||||
if (mUserHistoryDictionary != null) mUserHistoryDictionary.flushPendingWrites();
|
if (mUserHistoryDictionary != null) mUserHistoryDictionary.flushPendingWrites();
|
||||||
|
@ -779,12 +742,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
mHandler.cancelUpdateSuggestions();
|
mHandler.cancelUpdateSuggestions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onUpdateExtractedText(int token, ExtractedText text) {
|
|
||||||
super.onUpdateExtractedText(token, text);
|
|
||||||
mVoiceProxy.showPunctuationHintIfNecessary();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpdateSelection(int oldSelStart, int oldSelEnd,
|
public void onUpdateSelection(int oldSelStart, int oldSelEnd,
|
||||||
int newSelStart, int newSelEnd,
|
int newSelStart, int newSelEnd,
|
||||||
|
@ -816,8 +773,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
+ ", ce=" + composingSpanEnd);
|
+ ", ce=" + composingSpanEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
mVoiceProxy.setCursorAndSelection(newSelEnd, newSelStart);
|
|
||||||
|
|
||||||
// TODO: refactor the following code to be less contrived.
|
// TODO: refactor the following code to be less contrived.
|
||||||
// "newSelStart != composingSpanEnd" || "newSelEnd != composingSpanEnd" means
|
// "newSelStart != composingSpanEnd" || "newSelEnd != composingSpanEnd" means
|
||||||
// that the cursor is not at the end of the composing span, or there is a selection.
|
// that the cursor is not at the end of the composing span, or there is a selection.
|
||||||
|
@ -905,7 +860,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
mOptionsDialog.dismiss();
|
mOptionsDialog.dismiss();
|
||||||
mOptionsDialog = null;
|
mOptionsDialog = null;
|
||||||
}
|
}
|
||||||
mVoiceProxy.hideVoiceWindow();
|
|
||||||
super.hideWindow();
|
super.hideWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1094,7 +1048,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
if (ic != null) {
|
if (ic != null) {
|
||||||
ic.finishComposingText();
|
ic.finishComposingText();
|
||||||
}
|
}
|
||||||
mVoiceProxy.setVoiceInputHighlighted(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetComposingState(final boolean alsoResetLastComposedWord) {
|
private void resetComposingState(final boolean alsoResetLastComposedWord) {
|
||||||
|
@ -1184,14 +1137,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
|
|
||||||
private void onSettingsKeyPressed() {
|
private void onSettingsKeyPressed() {
|
||||||
if (isShowingOptionDialog()) return;
|
if (isShowingOptionDialog()) return;
|
||||||
if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) {
|
showSubtypeSelectorAndSettings();
|
||||||
showSubtypeSelectorAndSettings();
|
|
||||||
} else if (SubtypeUtils.hasMultipleEnabledIMEsOrSubtypes(
|
|
||||||
false /* exclude aux subtypes */)) {
|
|
||||||
showOptionsMenu();
|
|
||||||
} else {
|
|
||||||
launchSettings();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Virtual codes representing custom requests. These are used in onCustomRequest() below.
|
// Virtual codes representing custom requests. These are used in onCustomRequest() below.
|
||||||
|
@ -1351,7 +1297,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTextInput(CharSequence text) {
|
public void onTextInput(CharSequence text) {
|
||||||
mVoiceProxy.commitVoiceInput();
|
|
||||||
final InputConnection ic = getCurrentInputConnection();
|
final InputConnection ic = getCurrentInputConnection();
|
||||||
if (ic == null) return;
|
if (ic == null) return;
|
||||||
ic.beginBatchEdit();
|
ic.beginBatchEdit();
|
||||||
|
@ -1396,7 +1341,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleBackspace(final int spaceState) {
|
private void handleBackspace(final int spaceState) {
|
||||||
if (mVoiceProxy.logAndRevertVoiceInput()) return;
|
|
||||||
final InputConnection ic = getCurrentInputConnection();
|
final InputConnection ic = getCurrentInputConnection();
|
||||||
if (ic == null) return;
|
if (ic == null) return;
|
||||||
ic.beginBatchEdit();
|
ic.beginBatchEdit();
|
||||||
|
@ -1406,8 +1350,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
|
|
||||||
// "ic" may not be null.
|
// "ic" may not be null.
|
||||||
private void handleBackspaceWhileInBatchEdit(final int spaceState, final InputConnection ic) {
|
private void handleBackspaceWhileInBatchEdit(final int spaceState, final InputConnection ic) {
|
||||||
mVoiceProxy.handleBackspace();
|
|
||||||
|
|
||||||
// In many cases, we may have to put the keyboard in auto-shift state again.
|
// In many cases, we may have to put the keyboard in auto-shift state again.
|
||||||
mHandler.postUpdateShiftState();
|
mHandler.postUpdateShiftState();
|
||||||
|
|
||||||
|
@ -1506,7 +1448,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
|
|
||||||
private void handleCharacter(final int primaryCode, final int x,
|
private void handleCharacter(final int primaryCode, final int x,
|
||||||
final int y, final int spaceState) {
|
final int y, final int spaceState) {
|
||||||
mVoiceProxy.handleCharacter();
|
|
||||||
final InputConnection ic = getCurrentInputConnection();
|
final InputConnection ic = getCurrentInputConnection();
|
||||||
if (null != ic) ic.beginBatchEdit();
|
if (null != ic) ic.beginBatchEdit();
|
||||||
// TODO: if ic is null, does it make any sense to call this?
|
// TODO: if ic is null, does it make any sense to call this?
|
||||||
|
@ -1582,8 +1523,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
// Returns true if we did an autocorrection, false otherwise.
|
// Returns true if we did an autocorrection, false otherwise.
|
||||||
private boolean handleSeparator(final int primaryCode, final int x, final int y,
|
private boolean handleSeparator(final int primaryCode, final int x, final int y,
|
||||||
final int spaceState) {
|
final int spaceState) {
|
||||||
mVoiceProxy.handleSeparator();
|
|
||||||
|
|
||||||
// Should dismiss the "Touch again to save" message when handling separator
|
// Should dismiss the "Touch again to save" message when handling separator
|
||||||
if (mSuggestionsView != null && mSuggestionsView.dismissAddToDictionaryHint()) {
|
if (mSuggestionsView != null && mSuggestionsView.dismissAddToDictionaryHint()) {
|
||||||
mHandler.cancelUpdateBigramPredictions();
|
mHandler.cancelUpdateBigramPredictions();
|
||||||
|
@ -1669,7 +1608,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
|
|
||||||
private void handleClose() {
|
private void handleClose() {
|
||||||
commitTyped(getCurrentInputConnection(), LastComposedWord.NOT_A_SEPARATOR);
|
commitTyped(getCurrentInputConnection(), LastComposedWord.NOT_A_SEPARATOR);
|
||||||
mVoiceProxy.handleClose();
|
|
||||||
requestHideSelf(0);
|
requestHideSelf(0);
|
||||||
LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
|
LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
|
||||||
if (inputView != null)
|
if (inputView != null)
|
||||||
|
@ -1749,8 +1687,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
|
|
||||||
public void updateSuggestions() {
|
public void updateSuggestions() {
|
||||||
// Check if we have a suggestion engine attached.
|
// Check if we have a suggestion engine attached.
|
||||||
if ((mSuggest == null || !isSuggestionsRequested())
|
if ((mSuggest == null || !isSuggestionsRequested())) {
|
||||||
&& !mVoiceProxy.isVoiceInputHighlighted()) {
|
|
||||||
if (mWordComposer.isComposingWord()) {
|
if (mWordComposer.isComposingWord()) {
|
||||||
Log.w(TAG, "Called updateSuggestions but suggestions were not requested!");
|
Log.w(TAG, "Called updateSuggestions but suggestions were not requested!");
|
||||||
mWordComposer.setAutoCorrection(mWordComposer.getTypedWord());
|
mWordComposer.setAutoCorrection(mWordComposer.getTypedWord());
|
||||||
|
@ -1859,8 +1796,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
@Override
|
@Override
|
||||||
public void pickSuggestionManually(final int index, final CharSequence suggestion) {
|
public void pickSuggestionManually(final int index, final CharSequence suggestion) {
|
||||||
final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions();
|
final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions();
|
||||||
mVoiceProxy.flushAndLogAllTextModificationCounters(index, suggestion,
|
|
||||||
mSettingsValues.mWordSeparators);
|
|
||||||
|
|
||||||
if (SPACE_STATE_PHANTOM == mSpaceState && suggestion.length() > 0) {
|
if (SPACE_STATE_PHANTOM == mSpaceState && suggestion.length() > 0) {
|
||||||
int firstChar = Character.codePointAt(suggestion, 0);
|
int firstChar = Character.codePointAt(suggestion, 0);
|
||||||
|
@ -1953,7 +1888,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
final int separatorCode) {
|
final int separatorCode) {
|
||||||
final InputConnection ic = getCurrentInputConnection();
|
final InputConnection ic = getCurrentInputConnection();
|
||||||
if (ic != null) {
|
if (ic != null) {
|
||||||
mVoiceProxy.rememberReplacedWord(bestWord, mSettingsValues.mWordSeparators);
|
|
||||||
if (mSettingsValues.mEnableSuggestionSpanInsertion) {
|
if (mSettingsValues.mEnableSuggestionSpanInsertion) {
|
||||||
final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions();
|
final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions();
|
||||||
ic.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan(
|
ic.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan(
|
||||||
|
@ -2206,11 +2140,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
// Notify that language or mode have been changed and toggleLanguage will update KeyboardID
|
// Notify that language or mode have been changed and toggleLanguage will update KeyboardID
|
||||||
// according to new language or mode.
|
// according to new language or mode.
|
||||||
public void onRefreshKeyboard() {
|
public void onRefreshKeyboard() {
|
||||||
if (!CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) {
|
|
||||||
// Before Honeycomb, Voice IME is in LatinIME and it changes the current input view,
|
|
||||||
// so that we need to re-create the keyboard input view here.
|
|
||||||
setInputView(mKeyboardSwitcher.onCreateInputView());
|
|
||||||
}
|
|
||||||
// When the device locale is changed in SetupWizard etc., this method may get called via
|
// When the device locale is changed in SetupWizard etc., this method may get called via
|
||||||
// onConfigurationChanged before SoftInputWindow is shown.
|
// onConfigurationChanged before SoftInputWindow is shown.
|
||||||
if (mKeyboardSwitcher.getKeyboardView() != null) {
|
if (mKeyboardSwitcher.getKeyboardView() != null) {
|
||||||
|
@ -2269,11 +2198,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: remove this method when VoiceProxy has been removed
|
|
||||||
public void vibrate() {
|
|
||||||
mFeedbackManager.vibrate(mKeyboardSwitcher.getKeyboardView());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateCorrectionMode() {
|
private void updateCorrectionMode() {
|
||||||
// TODO: cleanup messy flags
|
// TODO: cleanup messy flags
|
||||||
final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled
|
final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled
|
||||||
|
@ -2341,32 +2265,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
showOptionDialogInternal(builder.create());
|
showOptionDialogInternal(builder.create());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showOptionsMenu() {
|
|
||||||
final CharSequence title = getString(R.string.english_ime_input_options);
|
|
||||||
final CharSequence[] items = new CharSequence[] {
|
|
||||||
getString(R.string.selectInputMethod),
|
|
||||||
getString(R.string.english_ime_settings),
|
|
||||||
};
|
|
||||||
final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface di, int position) {
|
|
||||||
di.dismiss();
|
|
||||||
switch (position) {
|
|
||||||
case 0:
|
|
||||||
mImm.showInputMethodPicker();
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
launchSettings();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
final AlertDialog.Builder builder = new AlertDialog.Builder(this)
|
|
||||||
.setItems(items, listener)
|
|
||||||
.setTitle(title);
|
|
||||||
showOptionDialogInternal(builder.create());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
|
protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
|
||||||
super.dump(fd, fout, args);
|
super.dump(fd, fout, args);
|
||||||
|
|
|
@ -45,15 +45,13 @@ import android.widget.TextView;
|
||||||
import com.android.inputmethod.compat.CompatUtils;
|
import com.android.inputmethod.compat.CompatUtils;
|
||||||
import com.android.inputmethod.compat.InputMethodServiceCompatWrapper;
|
import com.android.inputmethod.compat.InputMethodServiceCompatWrapper;
|
||||||
import com.android.inputmethod.compat.VibratorCompatWrapper;
|
import com.android.inputmethod.compat.VibratorCompatWrapper;
|
||||||
import com.android.inputmethod.deprecated.VoiceProxy;
|
|
||||||
import com.android.inputmethod.latin.define.ProductionFlag;
|
import com.android.inputmethod.latin.define.ProductionFlag;
|
||||||
import com.android.inputmethodcommon.InputMethodSettingsActivity;
|
import com.android.inputmethodcommon.InputMethodSettingsActivity;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public class Settings extends InputMethodSettingsActivity
|
public class Settings extends InputMethodSettingsActivity
|
||||||
implements SharedPreferences.OnSharedPreferenceChangeListener,
|
implements SharedPreferences.OnSharedPreferenceChangeListener, OnPreferenceClickListener {
|
||||||
DialogInterface.OnDismissListener, OnPreferenceClickListener {
|
|
||||||
private static final String TAG = Settings.class.getSimpleName();
|
private static final String TAG = Settings.class.getSimpleName();
|
||||||
|
|
||||||
public static final boolean ENABLE_EXPERIMENTAL_SETTINGS = false;
|
public static final boolean ENABLE_EXPERIMENTAL_SETTINGS = false;
|
||||||
|
@ -92,9 +90,6 @@ public class Settings extends InputMethodSettingsActivity
|
||||||
public static final String PREF_SELECTED_LANGUAGES = "selected_languages";
|
public static final String PREF_SELECTED_LANGUAGES = "selected_languages";
|
||||||
public static final String PREF_DEBUG_SETTINGS = "debug_settings";
|
public static final String PREF_DEBUG_SETTINGS = "debug_settings";
|
||||||
|
|
||||||
// Dialog ids
|
|
||||||
private static final int VOICE_INPUT_CONFIRM_DIALOG = 0;
|
|
||||||
|
|
||||||
private PreferenceScreen mInputLanguageSelection;
|
private PreferenceScreen mInputLanguageSelection;
|
||||||
private PreferenceScreen mKeypressVibrationDurationSettingsPref;
|
private PreferenceScreen mKeypressVibrationDurationSettingsPref;
|
||||||
private PreferenceScreen mKeypressSoundVolumeSettingsPref;
|
private PreferenceScreen mKeypressSoundVolumeSettingsPref;
|
||||||
|
@ -113,7 +108,6 @@ public class Settings extends InputMethodSettingsActivity
|
||||||
private TextView mKeypressVibrationDurationSettingsTextView;
|
private TextView mKeypressVibrationDurationSettingsTextView;
|
||||||
private TextView mKeypressSoundVolumeSettingsTextView;
|
private TextView mKeypressSoundVolumeSettingsTextView;
|
||||||
|
|
||||||
private boolean mOkClicked = false;
|
|
||||||
private String mVoiceModeOff;
|
private String mVoiceModeOff;
|
||||||
|
|
||||||
private void ensureConsistencyOfAutoCorrectionSettings() {
|
private void ensureConsistencyOfAutoCorrectionSettings() {
|
||||||
|
@ -291,9 +285,7 @@ public class Settings extends InputMethodSettingsActivity
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
final boolean isShortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled();
|
final boolean isShortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled();
|
||||||
if (isShortcutImeEnabled
|
if (isShortcutImeEnabled) {
|
||||||
|| (VoiceProxy.VOICE_INSTALLED
|
|
||||||
&& VoiceProxy.isRecognitionAvailable(getActivityInternal()))) {
|
|
||||||
updateVoiceModeSummary();
|
updateVoiceModeSummary();
|
||||||
} else {
|
} else {
|
||||||
getPreferenceScreen().removePreference(mVoicePreference);
|
getPreferenceScreen().removePreference(mVoicePreference);
|
||||||
|
@ -312,13 +304,7 @@ public class Settings extends InputMethodSettingsActivity
|
||||||
@Override
|
@Override
|
||||||
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
|
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
|
||||||
(new BackupManager(getActivityInternal())).dataChanged();
|
(new BackupManager(getActivityInternal())).dataChanged();
|
||||||
// If turning on voice input, show dialog
|
if (key.equals(PREF_POPUP_ON)) {
|
||||||
if (key.equals(PREF_VOICE_MODE) && !mVoiceOn) {
|
|
||||||
if (!prefs.getString(PREF_VOICE_MODE, mVoiceModeOff)
|
|
||||||
.equals(mVoiceModeOff)) {
|
|
||||||
showVoiceConfirmation();
|
|
||||||
}
|
|
||||||
} else if (key.equals(PREF_POPUP_ON)) {
|
|
||||||
final ListPreference popupDismissDelay =
|
final ListPreference popupDismissDelay =
|
||||||
(ListPreference)findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
|
(ListPreference)findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
|
||||||
if (null != popupDismissDelay) {
|
if (null != popupDismissDelay) {
|
||||||
|
@ -363,80 +349,12 @@ public class Settings extends InputMethodSettingsActivity
|
||||||
lp.setSummary(lp.getEntries()[lp.findIndexOfValue(lp.getValue())]);
|
lp.setSummary(lp.getEntries()[lp.findIndexOfValue(lp.getValue())]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showVoiceConfirmation() {
|
|
||||||
mOkClicked = false;
|
|
||||||
getActivityInternal().showDialog(VOICE_INPUT_CONFIRM_DIALOG);
|
|
||||||
// Make URL in the dialog message clickable
|
|
||||||
if (mDialog != null) {
|
|
||||||
TextView textView = (TextView) mDialog.findViewById(android.R.id.message);
|
|
||||||
if (textView != null) {
|
|
||||||
textView.setMovementMethod(LinkMovementMethod.getInstance());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateVoiceModeSummary() {
|
private void updateVoiceModeSummary() {
|
||||||
mVoicePreference.setSummary(
|
mVoicePreference.setSummary(
|
||||||
getResources().getStringArray(R.array.voice_input_modes_summary)
|
getResources().getStringArray(R.array.voice_input_modes_summary)
|
||||||
[mVoicePreference.findIndexOfValue(mVoicePreference.getValue())]);
|
[mVoicePreference.findIndexOfValue(mVoicePreference.getValue())]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Dialog onCreateDialog(int id) {
|
|
||||||
switch (id) {
|
|
||||||
case VOICE_INPUT_CONFIRM_DIALOG:
|
|
||||||
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int whichButton) {
|
|
||||||
if (whichButton == DialogInterface.BUTTON_NEGATIVE) {
|
|
||||||
mVoicePreference.setValue(mVoiceModeOff);
|
|
||||||
} else if (whichButton == DialogInterface.BUTTON_POSITIVE) {
|
|
||||||
mOkClicked = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivityInternal())
|
|
||||||
.setTitle(R.string.voice_warning_title)
|
|
||||||
.setPositiveButton(android.R.string.ok, listener)
|
|
||||||
.setNegativeButton(android.R.string.cancel, listener);
|
|
||||||
|
|
||||||
// Get the current list of supported locales and check the current locale against
|
|
||||||
// that list, to decide whether to put a warning that voice input will not work in
|
|
||||||
// the current language as part of the pop-up confirmation dialog.
|
|
||||||
boolean localeSupported = SubtypeSwitcher.isVoiceSupported(
|
|
||||||
this, Locale.getDefault().toString());
|
|
||||||
|
|
||||||
final CharSequence message;
|
|
||||||
if (localeSupported) {
|
|
||||||
message = TextUtils.concat(
|
|
||||||
getText(R.string.voice_warning_may_not_understand), "\n\n",
|
|
||||||
getText(R.string.voice_hint_dialog_message));
|
|
||||||
} else {
|
|
||||||
message = TextUtils.concat(
|
|
||||||
getText(R.string.voice_warning_locale_not_supported), "\n\n",
|
|
||||||
getText(R.string.voice_warning_may_not_understand), "\n\n",
|
|
||||||
getText(R.string.voice_hint_dialog_message));
|
|
||||||
}
|
|
||||||
builder.setMessage(message);
|
|
||||||
AlertDialog dialog = builder.create();
|
|
||||||
mDialog = dialog;
|
|
||||||
dialog.setOnDismissListener(this);
|
|
||||||
return dialog;
|
|
||||||
default:
|
|
||||||
Log.e(TAG, "unknown dialog " + id);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDismiss(DialogInterface dialog) {
|
|
||||||
if (!mOkClicked) {
|
|
||||||
// This assumes that onPreferenceClick gets called first, and this if the user
|
|
||||||
// agreed after the warning, we set the mOkClicked value to true.
|
|
||||||
mVoicePreference.setValue(mVoiceModeOff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refreshEnablingsOfKeypressSoundAndVibrationSettings(
|
private void refreshEnablingsOfKeypressSoundAndVibrationSettings(
|
||||||
SharedPreferences sp, Resources res) {
|
SharedPreferences sp, Resources res) {
|
||||||
if (mKeypressVibrationDurationSettingsPref != null) {
|
if (mKeypressVibrationDurationSettingsPref != null) {
|
||||||
|
|
|
@ -33,7 +33,6 @@ import android.util.Log;
|
||||||
import com.android.inputmethod.compat.InputMethodInfoCompatWrapper;
|
import com.android.inputmethod.compat.InputMethodInfoCompatWrapper;
|
||||||
import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
|
import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
|
||||||
import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper;
|
import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper;
|
||||||
import com.android.inputmethod.deprecated.VoiceProxy;
|
|
||||||
import com.android.inputmethod.keyboard.KeyboardSwitcher;
|
import com.android.inputmethod.keyboard.KeyboardSwitcher;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -76,7 +75,6 @@ public class SubtypeSwitcher {
|
||||||
private Locale mSystemLocale;
|
private Locale mSystemLocale;
|
||||||
private Locale mInputLocale;
|
private Locale mInputLocale;
|
||||||
private String mInputLocaleStr;
|
private String mInputLocaleStr;
|
||||||
private VoiceProxy.VoiceInputWrapper mVoiceInputWrapper;
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
private boolean mIsNetworkConnected;
|
private boolean mIsNetworkConnected;
|
||||||
|
@ -108,7 +106,6 @@ public class SubtypeSwitcher {
|
||||||
mInputLocaleStr = null;
|
mInputLocaleStr = null;
|
||||||
mCurrentSubtype = null;
|
mCurrentSubtype = null;
|
||||||
mAllEnabledSubtypesOfCurrentInputMethod = null;
|
mAllEnabledSubtypesOfCurrentInputMethod = null;
|
||||||
mVoiceInputWrapper = null;
|
|
||||||
|
|
||||||
final NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
|
final NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
|
||||||
mIsNetworkConnected = (info != null && info.isConnected());
|
mIsNetworkConnected = (info != null && info.isConnected());
|
||||||
|
@ -234,34 +231,12 @@ public class SubtypeSwitcher {
|
||||||
}
|
}
|
||||||
mCurrentSubtype = newSubtype;
|
mCurrentSubtype = newSubtype;
|
||||||
|
|
||||||
// If the old mode is voice input, we need to reset or cancel its status.
|
|
||||||
// We cancel its status when we change mode, while we reset otherwise.
|
|
||||||
if (isKeyboardMode()) {
|
if (isKeyboardMode()) {
|
||||||
if (modeChanged) {
|
|
||||||
if (VOICE_MODE.equals(oldMode) && mVoiceInputWrapper != null) {
|
|
||||||
mVoiceInputWrapper.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (modeChanged || languageChanged) {
|
if (modeChanged || languageChanged) {
|
||||||
updateShortcutIME();
|
updateShortcutIME();
|
||||||
mService.onRefreshKeyboard();
|
mService.onRefreshKeyboard();
|
||||||
}
|
}
|
||||||
} else if (isVoiceMode() && mVoiceInputWrapper != null) {
|
|
||||||
if (VOICE_MODE.equals(oldMode)) {
|
|
||||||
mVoiceInputWrapper.reset();
|
|
||||||
}
|
|
||||||
// If needsToShowWarningDialog is true, voice input need to show warning before
|
|
||||||
// show recognition view.
|
|
||||||
if (languageChanged || modeChanged
|
|
||||||
|| VoiceProxy.getInstance().needsToShowWarningDialog()) {
|
|
||||||
triggerVoiceIME();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (VOICE_MODE.equals(oldMode) && mVoiceInputWrapper != null) {
|
|
||||||
// We need to reset the voice input to release the resources and to reset its status
|
|
||||||
// as it is not the current input mode.
|
|
||||||
mVoiceInputWrapper.reset();
|
|
||||||
}
|
|
||||||
final String packageName = mService.getPackageName();
|
final String packageName = mService.getPackageName();
|
||||||
int version = -1;
|
int version = -1;
|
||||||
try {
|
try {
|
||||||
|
@ -270,7 +245,7 @@ public class SubtypeSwitcher {
|
||||||
} catch (NameNotFoundException e) {
|
} catch (NameNotFoundException e) {
|
||||||
}
|
}
|
||||||
Log.w(TAG, "Unknown subtype mode: " + newMode + "," + version + ", " + packageName
|
Log.w(TAG, "Unknown subtype mode: " + newMode + "," + version + ", " + packageName
|
||||||
+ ", " + mVoiceInputWrapper + ". IME is already changed to other IME.");
|
+ ". IME is already changed to other IME.");
|
||||||
if (newSubtype != null) {
|
if (newSubtype != null) {
|
||||||
Log.w(TAG, "Subtype mode:" + newSubtype.getMode());
|
Log.w(TAG, "Subtype mode:" + newSubtype.getMode());
|
||||||
Log.w(TAG, "Subtype locale:" + newSubtype.getLocale());
|
Log.w(TAG, "Subtype locale:" + newSubtype.getLocale());
|
||||||
|
@ -477,40 +452,6 @@ public class SubtypeSwitcher {
|
||||||
return KEYBOARD_MODE.equals(getCurrentSubtypeMode());
|
return KEYBOARD_MODE.equals(getCurrentSubtypeMode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////
|
|
||||||
// Voice Input functions //
|
|
||||||
///////////////////////////
|
|
||||||
|
|
||||||
public boolean setVoiceInputWrapper(VoiceProxy.VoiceInputWrapper vi) {
|
|
||||||
if (mVoiceInputWrapper == null && vi != null) {
|
|
||||||
mVoiceInputWrapper = vi;
|
|
||||||
if (isVoiceMode()) {
|
|
||||||
if (DBG) {
|
|
||||||
Log.d(TAG, "Set and call voice input.: " + getInputLocaleStr());
|
|
||||||
}
|
|
||||||
triggerVoiceIME();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isVoiceMode() {
|
|
||||||
return null == mCurrentSubtype ? false : VOICE_MODE.equals(getCurrentSubtypeMode());
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDummyVoiceMode() {
|
|
||||||
return mCurrentSubtype != null && mCurrentSubtype.getOriginalObject() == null
|
|
||||||
&& VOICE_MODE.equals(getCurrentSubtypeMode());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void triggerVoiceIME() {
|
|
||||||
if (!mService.isInputViewShown()) return;
|
|
||||||
VoiceProxy.getInstance().startListening(false,
|
|
||||||
KeyboardSwitcher.getInstance().getKeyboardView().getWindowToken());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getInputLanguageName() {
|
public String getInputLanguageName() {
|
||||||
return StringUtils.getDisplayLanguage(getInputLocale());
|
return StringUtils.getDisplayLanguage(getInputLocale());
|
||||||
}
|
}
|
||||||
|
@ -537,18 +478,4 @@ public class SubtypeSwitcher {
|
||||||
public String getCurrentSubtypeMode() {
|
public String getCurrentSubtypeMode() {
|
||||||
return null != mCurrentSubtype ? mCurrentSubtype.getMode() : KEYBOARD_MODE;
|
return null != mCurrentSubtype ? mCurrentSubtype.getMode() : KEYBOARD_MODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static boolean isVoiceSupported(Context context, String locale) {
|
|
||||||
// Get the current list of supported locales and check the current locale against that
|
|
||||||
// list. We cache this value so as not to check it every time the user starts a voice
|
|
||||||
// input. Because this method is called by onStartInputView, this should mean that as
|
|
||||||
// long as the locale doesn't change while the user is keeping the IME open, the
|
|
||||||
// value should never be stale.
|
|
||||||
String supportedLocalesString = VoiceProxy.getSupportedLocalesString(
|
|
||||||
context.getContentResolver());
|
|
||||||
List<String> voiceInputSupportedLocales = Arrays.asList(
|
|
||||||
supportedLocalesString.split("\\s+"));
|
|
||||||
return voiceInputSupportedLocales.contains(locale);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue