Merge remote branch 'goog/master' into merge

Conflicts:
	java/src/com/android/inputmethod/latin/Settings.java
	java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
	java/src/com/android/inputmethod/voice/VoiceIMEConnector.java

Change-Id: If30410c4814c3224f87698c165312494c0efca23
main
satok 2011-01-19 20:33:55 +09:00
commit 9c383385d5
63 changed files with 1254 additions and 537 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
**
** Copyright 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.
*/
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="#ff000000"
android:endColor="#ff000e29"
android:angle="90" />
</shape>

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
**
** Copyright 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.
*/
-->
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_window_focused="false"
android:state_enabled="true"
android:drawable="@drawable/btn_center_default" />
<item
android:state_pressed="true"
android:drawable="@drawable/btn_center_pressed" />
<item
android:state_focused="true"
android:state_enabled="true"
android:drawable="@drawable/btn_center_selected" />
<item
android:state_enabled="true"
android:drawable="@drawable/btn_center_default" />
<item
android:drawable="@drawable/btn_center_default" />
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

BIN
java/res/drawable/caution.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -16,83 +16,70 @@
** See the License for the specific language governing permissions and ** See the License for the specific language governing permissions and
** limitations under the License. ** limitations under the License.
*/ */
--> -->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:background="@android:color/black"
android:paddingBottom="0dip"
android:paddingLeft="0dip"
android:paddingRight="0dip"
>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_image"
android:orientation="vertical"
android:background="@drawable/voice_ime_background"
android:scaleType="fitXY"
android:layout_width="match_parent"
android:layout_height="180dip"
android:paddingBottom="2dip"
android:paddingTop="2dip"
>
<TextView android:id="@+id/text"
android:text="@string/voice_initializing"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="15dip"
android:textSize="28sp"
android:textColor="#ffffff"
android:layout_gravity="center_horizontal"
/>
<ImageView android:id="@+id/image"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="20dip"
android:layout_gravity="center_horizontal"
android:src="@drawable/mic_slash_holo"
/>
<ProgressBar android:id="@+id/progress"
android:layout_height="60dip"
android:layout_width="60dip"
android:layout_gravity="center"
android:visibility="gone"
android:indeterminate="true"
android:indeterminateOnly="false"
/>
</LinearLayout>
<LinearLayout android:id="@+id/button"
android:orientation="vertical"
android:background="@drawable/ok_cancel"
android:scaleType="fitXY"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="42dip" android:background="@drawable/background_voice">
android:paddingLeft="1dip" <LinearLayout
android:paddingRight="1dip" xmlns:android="http://schemas.android.com/apk/res/android"
> android:id="@+id/popup_layout"
android:orientation="vertical"
<TextView android:id="@+id/button_text" android:layout_height="0dip"
android:text="@string/cancel" android:layout_width="500dip"
android:layout_height="wrap_content" android:layout_centerInParent="true"
android:layout_width="wrap_content" android:background="@drawable/vs_dialog_red">
android:layout_marginTop="7dip" <TextView
android:textSize="19sp" android:id="@+id/text"
android:textColor="#ffffff" android:text="@string/voice_error"
android:layout_gravity="center_horizontal" android:layout_height="wrap_content"
/> android:layout_width="wrap_content"
android:singleLine="true"
android:layout_marginTop="10dip"
android:textSize="28sp"
android:textColor="#ffffff"
android:layout_gravity="center"
android:visibility="invisible"/>
<RelativeLayout
android:layout_height="0dip"
android:layout_width="match_parent"
android:layout_weight="1.0">
<com.android.inputmethod.voice.SoundIndicator
android:id="@+id/sound_indicator"
android:src="@drawable/mic_full"
android:background="@drawable/mic_base"
android:adjustViewBounds="true"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_centerInParent="true"
android:visibility="gone"/>
<ImageView
android:id="@+id/image"
android:src="@drawable/mic_slash"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_centerInParent="true"
android:visibility="visible"/>
<ProgressBar
android:id="@+id/progress"
android:indeterminate="true"
android:indeterminateOnly="false"
android:layout_height="60dip"
android:layout_width="60dip"
android:layout_centerInParent="true"
android:visibility="gone"/>
</RelativeLayout>
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="54dip"
android:singleLine="true"
android:focusable="true"
android:text="@string/cancel"
android:layout_gravity="center_horizontal"
android:background="@drawable/btn_center"
android:textColor="#ffffff"
android:textSize="19sp" />
</LinearLayout> </LinearLayout>
</RelativeLayout>
</LinearLayout>

View File

@ -22,12 +22,19 @@
<bool name="config_enable_show_settings_key_option">false</bool> <bool name="config_enable_show_settings_key_option">false</bool>
<bool name="config_enable_show_subtype_settings">false</bool> <bool name="config_enable_show_subtype_settings">false</bool>
<bool name="config_enable_show_voice_key_option">false</bool> <bool name="config_enable_show_voice_key_option">false</bool>
<bool name="config_enable_show_popup_on_keypress_option">false</bool>
<bool name="config_enable_show_recorrection_option">false</bool>
<bool name="config_enable_quick_fixes_option">false</bool>
<bool name="config_enable_bigram_suggestions_option">false</bool>
<bool name="config_candidate_highlight_font_color_enabled">false</bool> <bool name="config_candidate_highlight_font_color_enabled">false</bool>
<bool name="config_swipe_down_dismiss_keyboard_enabled">false</bool> <bool name="config_swipe_down_dismiss_keyboard_enabled">false</bool>
<bool name="config_sliding_key_input_enabled">false</bool> <bool name="config_sliding_key_input_enabled">false</bool>
<bool name="config_digit_popup_characters_enabled">false</bool> <bool name="config_digit_popup_characters_enabled">false</bool>
<!-- Whether or not Popup on key press is enabled by default --> <!-- Whether or not Popup on key press is enabled by default -->
<bool name="config_default_popup_preview">false</bool> <bool name="config_default_popup_preview">false</bool>
<bool name="config_use_spacebar_language_switcher">false</bool>
<!-- The language is never displayed if == 0, always displayed if < 0 -->
<integer name="config_delay_before_fadeout_language_on_spacebar">1200</integer>
<!-- This configuration is the index of the array {@link KeyboardSwitcher.KEYBOARD_THEMES}. --> <!-- This configuration is the index of the array {@link KeyboardSwitcher.KEYBOARD_THEMES}. -->
<string name="config_default_keyboard_theme_id" translatable="false">5</string> <string name="config_default_keyboard_theme_id" translatable="false">5</string>
<string name="config_text_size_of_language_on_spacebar" translatable="false">medium</string> <string name="config_text_size_of_language_on_spacebar" translatable="false">medium</string>

View File

@ -19,5 +19,5 @@
--> -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Default value of the visibility of the suggestion strip --> <!-- Default value of the visibility of the suggestion strip -->
<string name="prefs_suggestion_visibility_default_value" translatable="false">1</string> <string name="prefs_suggestion_visibility_default_value" translatable="false">2</string>
</resources> </resources>

View File

@ -25,12 +25,25 @@
<bool name="config_enable_show_settings_key_option">true</bool> <bool name="config_enable_show_settings_key_option">true</bool>
<bool name="config_enable_show_subtype_settings">true</bool> <bool name="config_enable_show_subtype_settings">true</bool>
<bool name="config_enable_show_voice_key_option">true</bool> <bool name="config_enable_show_voice_key_option">true</bool>
<bool name="config_enable_show_popup_on_keypress_option">true</bool>
<bool name="config_enable_show_recorrection_option">true</bool>
<bool name="config_enable_quick_fixes_option">true</bool>
<bool name="config_enable_bigram_suggestions_option">true</bool>
<bool name="config_enable_usability_study_mode_option">false</bool>
<bool name="config_candidate_highlight_font_color_enabled">true</bool> <bool name="config_candidate_highlight_font_color_enabled">true</bool>
<bool name="config_swipe_down_dismiss_keyboard_enabled">true</bool> <bool name="config_swipe_down_dismiss_keyboard_enabled">true</bool>
<bool name="config_sliding_key_input_enabled">true</bool> <bool name="config_sliding_key_input_enabled">true</bool>
<bool name="config_digit_popup_characters_enabled">true</bool> <bool name="config_digit_popup_characters_enabled">true</bool>
<!-- Whether or not Popup on key press is enabled by default --> <!-- Whether or not Popup on key press is enabled by default -->
<bool name="config_default_popup_preview">true</bool> <bool name="config_default_popup_preview">true</bool>
<!-- Default values for whether quick fixes and bigram suggestions are activated -->
<bool name="config_default_quick_fixes">true</bool>
<bool name="config_default_bigram_suggestions">true</bool>
<bool name="config_use_spacebar_language_switcher">true</bool>
<!-- The language is never displayed if == 0, always displayed if < 0 -->
<integer name="config_delay_before_fadeout_language_on_spacebar">-1</integer>
<integer name="config_duration_of_fadeout_language_on_spacebar">50</integer>
<integer name="config_final_fadeout_percentage_of_language_on_spacebar">15</integer>
<integer name="config_delay_before_preview">0</integer> <integer name="config_delay_before_preview">0</integer>
<integer name="config_delay_after_preview">10</integer> <integer name="config_delay_after_preview">10</integer>
<integer name="config_preview_fadein_anim_time">0</integer> <integer name="config_preview_fadein_anim_time">0</integer>

View File

@ -138,4 +138,14 @@
<item>4</item> <item>4</item>
<item>5</item> <item>5</item>
</string-array> </string-array>
<!-- Subtype locale name exceptions -->
<string-array name="subtype_locale_exception_keys">
<item>en_US</item>
<item>en_GB</item>
</string-array>
<string-array name="subtype_locale_exception_values">
<item>English (US)</item>
<item>English (UK)</item>
</string-array>
</resources> </resources>

View File

@ -22,7 +22,7 @@
<string name="english_ime_name">Android keyboard</string> <string name="english_ime_name">Android keyboard</string>
<!-- Title for Latin keyboard settings activity / dialog --> <!-- Title for Latin keyboard settings activity / dialog -->
<string name="english_ime_settings">Android keyboard settings</string> <string name="english_ime_settings">Android keyboard settings</string>
<!-- Title for Latin keyboard input options dialog --> <!-- Title for Latin keyboard input options dialog [CHAR LIMIT=25] -->
<string name="english_ime_input_options">Input options</string> <string name="english_ime_input_options">Input options</string>
<!-- Option to provide vibrate/haptic feedback on keypress --> <!-- Option to provide vibrate/haptic feedback on keypress -->
@ -34,8 +34,11 @@
<!-- Option to pop up the character with a larger font above soft keyboard --> <!-- Option to pop up the character with a larger font above soft keyboard -->
<string name="popup_on_keypress">Popup on keypress</string> <string name="popup_on_keypress">Popup on keypress</string>
<!-- Category title for general settings for Android keyboard -->
<string name="general_category">General</string>
<!-- Category title for text prediction --> <!-- Category title for text prediction -->
<string name="prediction_category">Word suggestion settings</string> <string name="prediction_category">Text correction</string>
<!-- Option to enable auto capitalization of sentences --> <!-- Option to enable auto capitalization of sentences -->
<string name="auto_cap">Auto-capitalization</string> <string name="auto_cap">Auto-capitalization</string>
@ -46,7 +49,7 @@
<string name="quick_fixes_summary">Corrects commonly typed mistakes</string> <string name="quick_fixes_summary">Corrects commonly typed mistakes</string>
<!-- Option to enable showing suggestions --> <!-- Option to enable showing suggestions -->
<string name="prefs_show_suggestions">Show suggestions</string> <string name="prefs_show_suggestions">Show correction suggestions</string>
<!-- Description for show suggestions --> <!-- Description for show suggestions -->
<string name="prefs_show_suggestions_summary">Display suggested words while typing</string> <string name="prefs_show_suggestions_summary">Display suggested words while typing</string>
<string name="prefs_suggestion_visibility_show_name">Always show</string> <string name="prefs_suggestion_visibility_show_name">Always show</string>
@ -111,15 +114,15 @@
<string name="voice_warning_locale_not_supported">Voice input is not currently supported for your language, but does work in English.</string> <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 <!-- Message of the warning dialog that shows when a user initiates voice input for
the first time, or turns it on in settings. --> 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> <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 <!-- 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. --> 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> <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 <!-- Message to show when user enables the voice input settings (which says
"Press the microphone button"). --> "Press the microphone button"). [CHAR LIMIT=100] -->
<string name="voice_hint_dialog_message">To use voice input, press the microphone button.</string> <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. --> <!-- Short message to tell the user the system is ready for them to speak. -->

View File

@ -57,7 +57,6 @@
<key-style <key-style
latin:styleName="nonSpecialBackgroundSpaceKeyStyle" latin:styleName="nonSpecialBackgroundSpaceKeyStyle"
latin:code="@integer/key_space" latin:code="@integer/key_space"
latin:keyIcon="@drawable/sym_keyboard_space_holo"
latin:iconPreview="@drawable/sym_keyboard_feedback_space" /> latin:iconPreview="@drawable/sym_keyboard_feedback_space" />
<key-style <key-style
latin:styleName="smileyKeyStyle" latin:styleName="smileyKeyStyle"
@ -66,6 +65,12 @@
latin:keyHintIcon="@drawable/hint_popup_holo" latin:keyHintIcon="@drawable/hint_popup_holo"
latin:popupCharacters="@string/alternates_for_smiley" latin:popupCharacters="@string/alternates_for_smiley"
latin:maxPopupKeyboardColumn="5" /> latin:maxPopupKeyboardColumn="5" />
<key-style
latin:styleName="settingsKeyStyle"
latin:code="@integer/key_settings"
latin:keyIcon="@drawable/sym_keyboard_settings_holo"
latin:iconPreview="@drawable/sym_keyboard_feedback_settings"
latin:parentStyle="functionalKeyStyle" />
<key-style <key-style
latin:styleName="micKeyStyle" latin:styleName="micKeyStyle"
latin:code="@integer/key_voice" latin:code="@integer/key_voice"
@ -102,12 +107,10 @@
<key-style <key-style
latin:styleName="spaceKeyStyle" latin:styleName="spaceKeyStyle"
latin:code="@integer/key_space" latin:code="@integer/key_space"
latin:keyIcon="@drawable/sym_bkeyboard_space"
latin:iconPreview="@drawable/sym_keyboard_feedback_space" /> latin:iconPreview="@drawable/sym_keyboard_feedback_space" />
<key-style <key-style
latin:styleName="nonSpecialBackgroundSpaceKeyStyle" latin:styleName="nonSpecialBackgroundSpaceKeyStyle"
latin:code="@integer/key_space" latin:code="@integer/key_space"
latin:keyIcon="@drawable/sym_bkeyboard_space"
latin:iconPreview="@drawable/sym_keyboard_feedback_space" /> latin:iconPreview="@drawable/sym_keyboard_feedback_space" />
<key-style <key-style
latin:styleName="smileyKeyStyle" latin:styleName="smileyKeyStyle"
@ -116,6 +119,12 @@
latin:keyHintIcon="@drawable/hint_popup_holo" latin:keyHintIcon="@drawable/hint_popup_holo"
latin:popupCharacters="@string/alternates_for_smiley" latin:popupCharacters="@string/alternates_for_smiley"
latin:maxPopupKeyboardColumn="5" /> latin:maxPopupKeyboardColumn="5" />
<key-style
latin:styleName="settingsKeyStyle"
latin:code="@integer/key_settings"
latin:keyIcon="@drawable/sym_bkeyboard_settings"
latin:iconPreview="@drawable/sym_keyboard_feedback_settings"
latin:parentStyle="functionalKeyStyle" />
<key-style <key-style
latin:styleName="micKeyStyle" latin:styleName="micKeyStyle"
latin:code="@integer/key_voice" latin:code="@integer/key_voice"

View File

@ -120,7 +120,10 @@
<!-- There is an empty area bellow the "More" key and left of the "space" key. To ignore <!-- There is an empty area bellow the "More" key and left of the "space" key. To ignore
the touch event on the area, "space" is intentionally not marked as a left edge key. --> the touch event on the area, "space" is intentionally not marked as a left edge key. -->
<Spacer <Spacer
latin:horizontalGap="16.406%p" /> latin:horizontalGap="8.362%p" />
<Key
latin:keyStyle="settingsKeyStyle"
latin:keyWidth="8.042%p" />
<Key <Key
latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle" latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle"
latin:keyWidth="24.127%p" /> latin:keyWidth="24.127%p" />

View File

@ -81,7 +81,6 @@
<key-style <key-style
latin:styleName="numSpaceKeyStyle" latin:styleName="numSpaceKeyStyle"
latin:code="@integer/key_space" latin:code="@integer/key_space"
latin:keyIcon="@drawable/sym_keyboard_space_holo"
latin:iconPreview="@drawable/sym_keyboard_feedback_space" /> latin:iconPreview="@drawable/sym_keyboard_feedback_space" />
</case> </case>
<case <case
@ -143,7 +142,6 @@
<key-style <key-style
latin:styleName="numSpaceKeyStyle" latin:styleName="numSpaceKeyStyle"
latin:code="@integer/key_space" latin:code="@integer/key_space"
latin:keyIcon="@drawable/sym_bkeyboard_space"
latin:iconPreview="@drawable/sym_keyboard_feedback_space" /> latin:iconPreview="@drawable/sym_keyboard_feedback_space" />
</case> </case>
</switch> </switch>

View File

@ -128,10 +128,13 @@
<!-- There is an empty area bellow the "More" key and left of the "space" key. To ignore <!-- There is an empty area bellow the "More" key and left of the "space" key. To ignore
the touch event on the area, "space" is intentionally not marked as a left edge key. --> the touch event on the area, "space" is intentionally not marked as a left edge key. -->
<Spacer <Spacer
latin:horizontalGap="20.427%p" /> latin:horizontalGap="12.340%p" />
<Key
latin:keyStyle="settingsKeyStyle"
latin:keyWidth="8.042%p" />
<Key <Key
latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle" latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle"
latin:keyWidth="16.085%p" /> latin:keyWidth="16.084%p" />
<Spacer <Spacer
latin:horizontalGap="8.479%p" /> latin:horizontalGap="8.479%p" />
<Key <Key

View File

@ -140,7 +140,10 @@
<!-- There is an empty area bellow the "More" key and left of the "space" key. To ignore <!-- There is an empty area bellow the "More" key and left of the "space" key. To ignore
the touch event on the area, "space" is intentionally not marked as a left edge key. --> the touch event on the area, "space" is intentionally not marked as a left edge key. -->
<Spacer <Spacer
latin:horizontalGap="16.406%p" /> latin:horizontalGap="8.362%p" />
<Key
latin:keyStyle="settingsKeyStyle"
latin:keyWidth="8.042%p" />
<Key <Key
latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle" latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle"
latin:keyWidth="24.127%p" /> latin:keyWidth="24.127%p" />

View File

@ -26,7 +26,9 @@
latin:keyWidth="8.042%p" latin:keyWidth="8.042%p"
> >
<Spacer <Spacer
latin:horizontalGap="16.404%p" /> latin:horizontalGap="8.362%p" />
<Key
latin:keyStyle="settingsKeyStyle" />
<switch> <switch>
<case <case
latin:mode="email" latin:mode="email"

View File

@ -149,7 +149,9 @@
latin:keyWidth="8.042%p" latin:keyWidth="8.042%p"
> >
<Spacer <Spacer
latin:horizontalGap="16.404%p" /> latin:horizontalGap="8.362%p" />
<Key
latin:keyStyle="settingsKeyStyle" />
<Key <Key
latin:keyLabel="/" /> latin:keyLabel="/" />
<Key <Key

View File

@ -135,7 +135,9 @@
latin:keyWidth="8.042%p" latin:keyWidth="8.042%p"
> >
<Spacer <Spacer
latin:horizontalGap="32.488%p" /> latin:horizontalGap="24.446%p" />
<Key
latin:keyStyle="settingsKeyStyle" />
<Key <Key
latin:keyStyle="spaceKeyStyle" latin:keyStyle="spaceKeyStyle"
latin:keyWidth="37.454%p" /> latin:keyWidth="37.454%p" />

View File

@ -4,9 +4,9 @@
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -18,62 +18,68 @@
android:title="@string/english_ime_settings" android:title="@string/english_ime_settings"
android:key="english_ime_settings"> android:key="english_ime_settings">
<CheckBoxPreference <PreferenceCategory
android:key="vibrate_on" android:title="@string/general_category"
android:title="@string/vibrate_on_keypress" android:key="general_settings">
android:persistent="true"
/>
<CheckBoxPreference <CheckBoxPreference
android:key="sound_on" android:key="auto_cap"
android:title="@string/sound_on_keypress" android:title="@string/auto_cap"
android:persistent="true" android:persistent="true"
/> android:defaultValue="true"
/>
<CheckBoxPreference <CheckBoxPreference
android:key="popup_on" android:key="vibrate_on"
android:title="@string/popup_on_keypress" android:title="@string/vibrate_on_keypress"
android:persistent="true" android:persistent="true"
android:defaultValue="@bool/config_default_popup_preview" />
/>
<CheckBoxPreference <CheckBoxPreference
android:key="recorrection_enabled" android:key="sound_on"
android:title="@string/prefs_enable_recorrection" android:title="@string/sound_on_keypress"
android:summary="@string/prefs_enable_recorrection_summary" android:persistent="true"
android:persistent="true" />
android:defaultValue="@bool/default_recorrection_enabled"
/>
<CheckBoxPreference <CheckBoxPreference
android:key="auto_cap" android:key="popup_on"
android:title="@string/auto_cap" android:title="@string/popup_on_keypress"
android:persistent="true" android:persistent="true"
android:defaultValue="true" android:defaultValue="@bool/config_default_popup_preview"
/> />
<ListPreference <CheckBoxPreference
android:key="settings_key" android:key="recorrection_enabled"
android:title="@string/prefs_settings_key" android:title="@string/prefs_enable_recorrection"
android:persistent="true" android:summary="@string/prefs_enable_recorrection_summary"
android:entryValues="@array/settings_key_modes_values" android:persistent="true"
android:entries="@array/settings_key_modes" android:defaultValue="@bool/default_recorrection_enabled"
android:defaultValue="@string/settings_key_mode_auto" />
/>
<ListPreference <ListPreference
android:key="voice_mode" android:key="settings_key"
android:title="@string/voice_input" android:title="@string/prefs_settings_key"
android:persistent="true" android:persistent="true"
android:entryValues="@array/voice_input_modes_values" android:entryValues="@array/settings_key_modes_values"
android:entries="@array/voice_input_modes" android:entries="@array/settings_key_modes"
android:defaultValue="@string/voice_mode_main" android:defaultValue="@string/settings_key_mode_auto"
/> />
<PreferenceScreen <ListPreference
android:key="subtype_settings" android:key="voice_mode"
android:title="@string/language_selection_title" android:title="@string/voice_input"
android:summary="@string/language_selection_summary" /> android:persistent="true"
android:entryValues="@array/voice_input_modes_values"
android:entries="@array/voice_input_modes"
android:defaultValue="@string/voice_mode_main"
/>
<PreferenceScreen
android:key="subtype_settings"
android:title="@string/language_selection_title"
android:summary="@string/language_selection_summary" />
</PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:title="@string/prediction_category" android:title="@string/prediction_category"
@ -87,16 +93,6 @@
android:defaultValue="true" android:defaultValue="true"
/> />
<ListPreference
android:key="show_suggestions_setting"
android:summary="@string/prefs_show_suggestions_summary"
android:title="@string/prefs_show_suggestions"
android:persistent="true"
android:entryValues="@array/prefs_suggestion_visibility_values"
android:entries="@array/prefs_suggestion_visibilities"
android:defaultValue="@string/prefs_suggestion_visibility_default_value"
/>
<ListPreference <ListPreference
android:key="auto_correction_threshold" android:key="auto_correction_threshold"
android:title="@string/auto_correction" android:title="@string/auto_correction"
@ -107,6 +103,16 @@
android:defaultValue="@string/auto_correction_threshold_mode_index_modest" android:defaultValue="@string/auto_correction_threshold_mode_index_modest"
/> />
<ListPreference
android:key="show_suggestions_setting"
android:summary="@string/prefs_show_suggestions_summary"
android:title="@string/prefs_show_suggestions"
android:persistent="true"
android:entryValues="@array/prefs_suggestion_visibility_values"
android:entries="@array/prefs_suggestion_visibilities"
android:defaultValue="@string/prefs_suggestion_visibility_default_value"
/>
<CheckBoxPreference <CheckBoxPreference
android:key="bigram_suggestion" android:key="bigram_suggestion"
android:title="@string/bigram_suggestion" android:title="@string/bigram_suggestion"

View File

@ -330,6 +330,10 @@ public class Keyboard {
return isAlphaKeyboard() && mShiftState.isManualTemporaryUpperCase(); return isAlphaKeyboard() && mShiftState.isManualTemporaryUpperCase();
} }
public boolean isManualTemporaryUpperCaseFromAuto() {
return isAlphaKeyboard() && mShiftState.isManualTemporaryUpperCaseFromAuto();
}
public KeyboardShiftState getKeyboardShiftState() { public KeyboardShiftState getKeyboardShiftState() {
return mShiftState; return mShiftState;
} }

View File

@ -24,26 +24,38 @@ public class KeyboardShiftState {
private static final int NORMAL = 0; private static final int NORMAL = 0;
private static final int MANUAL_SHIFTED = 1; private static final int MANUAL_SHIFTED = 1;
private static final int SHIFT_LOCKED = 2; private static final int MANUAL_SHIFTED_FROM_AUTO = 2;
private static final int AUTO_SHIFTED = 3; private static final int AUTO_SHIFTED = 3;
private static final int SHIFT_LOCK_SHIFTED = 4; private static final int SHIFT_LOCKED = 4;
private static final int SHIFT_LOCK_SHIFTED = 5;
private int mState = NORMAL; private int mState = NORMAL;
public boolean setShifted(boolean newShiftState) { public boolean setShifted(boolean newShiftState) {
final int oldState = mState; final int oldState = mState;
if (newShiftState) { if (newShiftState) {
if (oldState == NORMAL || oldState == AUTO_SHIFTED) { switch (oldState) {
case NORMAL:
mState = MANUAL_SHIFTED; mState = MANUAL_SHIFTED;
} else if (oldState == SHIFT_LOCKED) { break;
case AUTO_SHIFTED:
mState = MANUAL_SHIFTED_FROM_AUTO;
break;
case SHIFT_LOCKED:
mState = SHIFT_LOCK_SHIFTED; mState = SHIFT_LOCK_SHIFTED;
break;
} }
} else { } else {
if (oldState == MANUAL_SHIFTED || oldState == AUTO_SHIFTED) { switch (oldState) {
case MANUAL_SHIFTED:
case MANUAL_SHIFTED_FROM_AUTO:
case AUTO_SHIFTED:
mState = NORMAL; mState = NORMAL;
} else if (oldState == SHIFT_LOCK_SHIFTED) { break;
case SHIFT_LOCK_SHIFTED:
mState = SHIFT_LOCKED; mState = SHIFT_LOCKED;
} break;
}
} }
if (DEBUG) if (DEBUG)
Log.d(TAG, "setShifted(" + newShiftState + "): " + toString(oldState) + " > " + this); Log.d(TAG, "setShifted(" + newShiftState + "): " + toString(oldState) + " > " + this);
@ -53,11 +65,21 @@ public class KeyboardShiftState {
public void setShiftLocked(boolean newShiftLockState) { public void setShiftLocked(boolean newShiftLockState) {
final int oldState = mState; final int oldState = mState;
if (newShiftLockState) { if (newShiftLockState) {
if (oldState == NORMAL || oldState == MANUAL_SHIFTED || oldState == AUTO_SHIFTED) switch (oldState) {
case NORMAL:
case MANUAL_SHIFTED:
case MANUAL_SHIFTED_FROM_AUTO:
case AUTO_SHIFTED:
mState = SHIFT_LOCKED; mState = SHIFT_LOCKED;
break;
}
} else { } else {
if (oldState == SHIFT_LOCKED || oldState == SHIFT_LOCK_SHIFTED) switch (oldState) {
case SHIFT_LOCKED:
case SHIFT_LOCK_SHIFTED:
mState = NORMAL; mState = NORMAL;
break;
}
} }
if (DEBUG) if (DEBUG)
Log.d(TAG, "setShiftLocked(" + newShiftLockState + "): " + toString(oldState) Log.d(TAG, "setShiftLocked(" + newShiftLockState + "): " + toString(oldState)
@ -84,7 +106,12 @@ public class KeyboardShiftState {
} }
public boolean isManualTemporaryUpperCase() { public boolean isManualTemporaryUpperCase() {
return mState == MANUAL_SHIFTED || mState == SHIFT_LOCK_SHIFTED; return mState == MANUAL_SHIFTED || mState == MANUAL_SHIFTED_FROM_AUTO
|| mState == SHIFT_LOCK_SHIFTED;
}
public boolean isManualTemporaryUpperCaseFromAuto() {
return mState == MANUAL_SHIFTED_FROM_AUTO;
} }
@Override @Override
@ -96,8 +123,9 @@ public class KeyboardShiftState {
switch (state) { switch (state) {
case NORMAL: return "NORMAL"; case NORMAL: return "NORMAL";
case MANUAL_SHIFTED: return "MANUAL_SHIFTED"; case MANUAL_SHIFTED: return "MANUAL_SHIFTED";
case SHIFT_LOCKED: return "SHIFT_LOCKED"; case MANUAL_SHIFTED_FROM_AUTO: return "MANUAL_SHIFTED_FROM_AUTO";
case AUTO_SHIFTED: return "AUTO_SHIFTED"; case AUTO_SHIFTED: return "AUTO_SHIFTED";
case SHIFT_LOCKED: return "SHIFT_LOCKED";
case SHIFT_LOCK_SHIFTED: return "SHIFT_LOCK_SHIFTED"; case SHIFT_LOCK_SHIFTED: return "SHIFT_LOCK_SHIFTED";
default: return "UKNOWN"; default: return "UKNOWN";
} }

View File

@ -157,7 +157,15 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
boolean voiceButtonOnPrimary) { boolean voiceButtonOnPrimary) {
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA; mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA;
try { try {
if (mInputView == null) return;
final Keyboard oldKeyboard = mInputView.getKeyboard();
loadKeyboardInternal(mode, imeOptions, voiceKeyEnabled, voiceButtonOnPrimary, false); loadKeyboardInternal(mode, imeOptions, voiceKeyEnabled, voiceButtonOnPrimary, false);
final Keyboard newKeyboard = mInputView.getKeyboard();
if (newKeyboard.isAlphaKeyboard()) {
final boolean localeChanged = (oldKeyboard == null)
|| !newKeyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale);
mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged);
}
} catch (RuntimeException e) { } catch (RuntimeException e) {
Log.w(TAG, e); Log.w(TAG, e);
LatinImeLogger.logOnException(mode + "," + imeOptions, e); LatinImeLogger.logOnException(mode + "," + imeOptions, e);
@ -167,7 +175,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private void loadKeyboardInternal(int mode, int imeOptions, boolean voiceButtonEnabled, private void loadKeyboardInternal(int mode, int imeOptions, boolean voiceButtonEnabled,
boolean voiceButtonOnPrimary, boolean isSymbols) { boolean voiceButtonOnPrimary, boolean isSymbols) {
if (mInputView == null) return; if (mInputView == null) return;
mInputView.setPreviewEnabled(mInputMethodService.getPopupOn());
mMode = mode; mMode = mode;
mImeOptions = imeOptions; mImeOptions = imeOptions;
@ -176,13 +183,16 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
mIsSymbols = isSymbols; mIsSymbols = isSymbols;
// Update the settings key state because number of enabled IMEs could have been changed // Update the settings key state because number of enabled IMEs could have been changed
mHasSettingsKey = getSettingsKeyMode(mPrefs, mInputMethodService); mHasSettingsKey = getSettingsKeyMode(mPrefs, mInputMethodService);
final KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols);
final Keyboard oldKeyboard = mInputView.getKeyboard();
if (oldKeyboard != null && oldKeyboard.mId.equals(id))
return;
makeSymbolsKeyboardIds(); makeSymbolsKeyboardIds();
KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols);
LatinKeyboard keyboard = getKeyboard(id);
mCurrentId = id; mCurrentId = id;
mInputView.setKeyboard(keyboard); mInputView.setPreviewEnabled(mInputMethodService.getPopupOn());
mInputView.setKeyboard(getKeyboard(id));
} }
private LatinKeyboard getKeyboard(KeyboardId id) { private LatinKeyboard getKeyboard(KeyboardId id) {
@ -210,6 +220,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
keyboard.onAutoCorrectionStateChanged(mIsAutoCorrectionActive); keyboard.onAutoCorrectionStateChanged(mIsAutoCorrectionActive);
keyboard.setShifted(false); keyboard.setShifted(false);
// If the cached keyboard had been switched to another keyboard while the language was
// displayed on its spacebar, it might have had arbitrary text fade factor. In such case,
// we should reset the text fade factor.
keyboard.setSpacebarTextFadeFactor(0.0f, null);
return keyboard; return keyboard;
} }
@ -313,6 +327,13 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
return false; return false;
} }
private boolean isManualTemporaryUpperCaseFromAuto() {
LatinKeyboard latinKeyboard = getLatinKeyboard();
if (latinKeyboard != null)
return latinKeyboard.isManualTemporaryUpperCaseFromAuto();
return false;
}
private void setManualTemporaryUpperCase(boolean shifted) { private void setManualTemporaryUpperCase(boolean shifted) {
LatinKeyboard latinKeyboard = getLatinKeyboard(); LatinKeyboard latinKeyboard = getLatinKeyboard();
if (latinKeyboard != null) { if (latinKeyboard != null) {
@ -468,6 +489,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
} else if (isShiftedOrShiftLocked() && shiftKeyState.isPressingOnShifted()) { } else if (isShiftedOrShiftLocked() && shiftKeyState.isPressingOnShifted()) {
// Shift has been pressed without chording while shifted state. // Shift has been pressed without chording while shifted state.
toggleShift(); toggleShift();
} else if (isManualTemporaryUpperCaseFromAuto() && shiftKeyState.isPressing()) {
// Shift has been pressed without chording while manual temporary upper case
// transited from automatic temporary upper case.
toggleShift();
} }
} }
shiftKeyState.onRelease(); shiftKeyState.onRelease();

View File

@ -298,8 +298,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
TypedArray a = context.obtainStyledAttributes( TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView); attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView);
LayoutInflater inflate =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int previewLayout = 0; int previewLayout = 0;
int keyTextSize = 0; int keyTextSize = 0;
@ -365,7 +363,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
mPreviewPopup = new PopupWindow(context); mPreviewPopup = new PopupWindow(context);
if (previewLayout != 0) { if (previewLayout != 0) {
mPreviewText = (TextView) inflate.inflate(previewLayout, null); mPreviewText = (TextView) LayoutInflater.from(context).inflate(previewLayout, null);
mPreviewTextSizeLarge = (int) res.getDimension(R.dimen.key_preview_text_size_large); mPreviewTextSizeLarge = (int) res.getDimension(R.dimen.key_preview_text_size_large);
mPreviewPopup.setContentView(mPreviewText); mPreviewPopup.setContentView(mPreviewText);
mPreviewPopup.setBackgroundDrawable(null); mPreviewPopup.setBackgroundDrawable(null);
@ -912,9 +910,8 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
// We should re-draw popup preview when 1) we need to hide the preview, 2) we will show // We should re-draw popup preview when 1) we need to hide the preview, 2) we will show
// the space key preview and 3) pointer moves off the space key to other letter key, we // the space key preview and 3) pointer moves off the space key to other letter key, we
// should hide the preview of the previous key. // should hide the preview of the previous key.
@SuppressWarnings("unused")
final boolean hidePreviewOrShowSpaceKeyPreview = (tracker == null) final boolean hidePreviewOrShowSpaceKeyPreview = (tracker == null)
|| (SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER || (SubtypeSwitcher.getInstance().useSpacebarLanguageSwitcher()
&& SubtypeSwitcher.getInstance().needsToDisplayLanguage() && SubtypeSwitcher.getInstance().needsToDisplayLanguage()
&& (tracker.isSpaceKey(keyIndex) || tracker.isSpaceKey(oldKeyIndex))); && (tracker.isSpaceKey(keyIndex) || tracker.isSpaceKey(oldKeyIndex)));
// If key changed and preview is on or the key is space (language switch is enabled) // If key changed and preview is on or the key is space (language switch is enabled)
@ -1081,9 +1078,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
private View inflateMiniKeyboardContainer(Key popupKey) { private View inflateMiniKeyboardContainer(Key popupKey) {
int popupKeyboardResId = mKeyboard.getPopupKeyboardResId(); int popupKeyboardResId = mKeyboard.getPopupKeyboardResId();
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService( View container = LayoutInflater.from(getContext()).inflate(mPopupLayout, null);
Context.LAYOUT_INFLATER_SERVICE);
View container = inflater.inflate(mPopupLayout, null);
if (container == null) if (container == null)
throw new NullPointerException(); throw new NullPointerException();
@ -1410,6 +1405,12 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
mBuffer = null; mBuffer = null;
mCanvas = null; mCanvas = null;
mMiniKeyboardCache.clear(); mMiniKeyboardCache.clear();
requestLayout();
}
public void purgeKeyboardAndClosing() {
mKeyboard = null;
closing();
} }
@Override @Override

View File

@ -24,6 +24,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.Paint.Align; import android.graphics.Paint.Align;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
@ -47,7 +48,9 @@ public class LatinKeyboard extends Keyboard {
private final Drawable mSpaceAutoCorrectionIndicator; private final Drawable mSpaceAutoCorrectionIndicator;
private final Drawable mButtonArrowLeftIcon; private final Drawable mButtonArrowLeftIcon;
private final Drawable mButtonArrowRightIcon; private final Drawable mButtonArrowRightIcon;
private final int mSpaceBarTextShadowColor; private final int mSpacebarTextColor;
private final int mSpacebarTextShadowColor;
private float mSpacebarTextFadeFactor = 0.0f;
private final int[] mSpaceKeyIndexArray; private final int[] mSpaceKeyIndexArray;
private int mSpaceDragStartX; private int mSpaceDragStartX;
private int mSpaceDragLastDiff; private int mSpaceDragLastDiff;
@ -80,11 +83,12 @@ public class LatinKeyboard extends Keyboard {
super(context, id.getXmlId(), id); super(context, id.getXmlId(), id);
final Resources res = context.getResources(); final Resources res = context.getResources();
mContext = context; mContext = context;
mSpacebarTextColor = res.getColor(R.color.latinkeyboard_bar_language_text);
if (id.mColorScheme == KeyboardView.COLOR_SCHEME_BLACK) { if (id.mColorScheme == KeyboardView.COLOR_SCHEME_BLACK) {
mSpaceBarTextShadowColor = res.getColor( mSpacebarTextShadowColor = res.getColor(
R.color.latinkeyboard_bar_language_shadow_black); R.color.latinkeyboard_bar_language_shadow_black);
} else { // default color scheme is KeyboardView.COLOR_SCHEME_WHITE } else { // default color scheme is KeyboardView.COLOR_SCHEME_WHITE
mSpaceBarTextShadowColor = res.getColor( mSpacebarTextShadowColor = res.getColor(
R.color.latinkeyboard_bar_language_shadow_white); R.color.latinkeyboard_bar_language_shadow_white);
} }
mSpaceAutoCorrectionIndicator = res.getDrawable(R.drawable.sym_keyboard_space_led); mSpaceAutoCorrectionIndicator = res.getDrawable(R.drawable.sym_keyboard_space_led);
@ -96,25 +100,38 @@ public class LatinKeyboard extends Keyboard {
mSpaceKeyIndexArray = new int[] { indexOf(CODE_SPACE) }; mSpaceKeyIndexArray = new int[] { indexOf(CODE_SPACE) };
} }
public void setSpacebarTextFadeFactor(float fadeFactor, LatinKeyboardView view) {
mSpacebarTextFadeFactor = fadeFactor;
updateSpacebarForLocale(false);
if (view != null)
view.invalidateKey(mSpaceKey);
}
private static int getSpacebarTextColor(int color, float fadeFactor) {
final int newColor = Color.argb((int)(Color.alpha(color) * fadeFactor),
Color.red(color), Color.green(color), Color.blue(color));
return newColor;
}
/** /**
* @return a key which should be invalidated. * @return a key which should be invalidated.
*/ */
public Key onAutoCorrectionStateChanged(boolean isAutoCorrection) { public Key onAutoCorrectionStateChanged(boolean isAutoCorrection) {
updateSpaceBarForLocale(isAutoCorrection); updateSpacebarForLocale(isAutoCorrection);
return mSpaceKey; return mSpaceKey;
} }
private void updateSpaceBarForLocale(boolean isAutoCorrection) { private void updateSpacebarForLocale(boolean isAutoCorrection) {
final Resources res = mContext.getResources(); final Resources res = mContext.getResources();
// If application locales are explicitly selected. // If application locales are explicitly selected.
if (SubtypeSwitcher.getInstance().needsToDisplayLanguage()) { if (SubtypeSwitcher.getInstance().needsToDisplayLanguage()) {
mSpaceKey.setIcon(new BitmapDrawable(res, mSpaceKey.setIcon(new BitmapDrawable(res,
drawSpaceBar(OPACITY_FULLY_OPAQUE, isAutoCorrection))); drawSpacebar(OPACITY_FULLY_OPAQUE, isAutoCorrection)));
} else { } else {
// sym_keyboard_space_led can be shared with Black and White symbol themes. // sym_keyboard_space_led can be shared with Black and White symbol themes.
if (isAutoCorrection) { if (isAutoCorrection) {
mSpaceKey.setIcon(new BitmapDrawable(res, mSpaceKey.setIcon(new BitmapDrawable(res,
drawSpaceBar(OPACITY_FULLY_OPAQUE, isAutoCorrection))); drawSpacebar(OPACITY_FULLY_OPAQUE, isAutoCorrection)));
} else { } else {
mSpaceKey.setIcon(mSpaceIcon); mSpaceKey.setIcon(mSpaceIcon);
} }
@ -128,8 +145,8 @@ public class LatinKeyboard extends Keyboard {
return bounds.width(); return bounds.width();
} }
// Layout local language name and left and right arrow on space bar. // Layout local language name and left and right arrow on spacebar.
private static String layoutSpaceBar(Paint paint, Locale locale, Drawable lArrow, private static String layoutSpacebar(Paint paint, Locale locale, Drawable lArrow,
Drawable rArrow, int width, int height, float origTextSize, Drawable rArrow, int width, int height, float origTextSize,
boolean allowVariableTextSize) { boolean allowVariableTextSize) {
final float arrowWidth = lArrow.getIntrinsicWidth(); final float arrowWidth = lArrow.getIntrinsicWidth();
@ -138,7 +155,7 @@ public class LatinKeyboard extends Keyboard {
final Rect bounds = new Rect(); final Rect bounds = new Rect();
// Estimate appropriate language name text size to fit in maxTextWidth. // Estimate appropriate language name text size to fit in maxTextWidth.
String language = SubtypeSwitcher.getDisplayLanguage(locale); String language = SubtypeSwitcher.getFullDisplayName(locale, true);
int textWidth = getTextWidth(paint, language, origTextSize, bounds); int textWidth = getTextWidth(paint, language, origTextSize, bounds);
// Assuming text width and text size are proportional to each other. // Assuming text width and text size are proportional to each other.
float textSize = origTextSize * Math.min(maxTextWidth / textWidth, 1.0f); float textSize = origTextSize * Math.min(maxTextWidth / textWidth, 1.0f);
@ -171,8 +188,7 @@ public class LatinKeyboard extends Keyboard {
return language; return language;
} }
@SuppressWarnings("unused") private Bitmap drawSpacebar(int opacity, boolean isAutoCorrection) {
private Bitmap drawSpaceBar(int opacity, boolean isAutoCorrection) {
final int width = mSpaceKey.mWidth; final int width = mSpaceKey.mWidth;
final int height = mSpaceIcon != null ? mSpaceIcon.getIntrinsicHeight() : mSpaceKey.mHeight; final int height = mSpaceIcon != null ? mSpaceIcon.getIntrinsicHeight() : mSpaceKey.mHeight;
final Bitmap buffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); final Bitmap buffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
@ -202,21 +218,25 @@ public class LatinKeyboard extends Keyboard {
} }
final boolean allowVariableTextSize = true; final boolean allowVariableTextSize = true;
final String language = layoutSpaceBar(paint, subtypeSwitcher.getInputLocale(), final String language = layoutSpacebar(paint, subtypeSwitcher.getInputLocale(),
mButtonArrowLeftIcon, mButtonArrowRightIcon, width, height, mButtonArrowLeftIcon, mButtonArrowRightIcon, width, height,
getTextSizeFromTheme(textStyle, defaultTextSize), getTextSizeFromTheme(textStyle, defaultTextSize),
allowVariableTextSize); allowVariableTextSize);
// Draw language text with shadow // Draw language text with shadow
final float baseline = height * SPACEBAR_LANGUAGE_BASELINE; // In case there is no space icon, we will place the language text at the center of
// spacebar.
final float descent = paint.descent(); final float descent = paint.descent();
paint.setColor(mSpaceBarTextShadowColor); final float textHeight = -paint.ascent() + descent;
final float baseline = (mSpaceIcon != null) ? height * SPACEBAR_LANGUAGE_BASELINE
: height / 2 + textHeight / 2;
paint.setColor(getSpacebarTextColor(mSpacebarTextShadowColor, mSpacebarTextFadeFactor));
canvas.drawText(language, width / 2, baseline - descent - 1, paint); canvas.drawText(language, width / 2, baseline - descent - 1, paint);
paint.setColor(res.getColor(R.color.latinkeyboard_bar_language_text)); paint.setColor(getSpacebarTextColor(mSpacebarTextColor, mSpacebarTextFadeFactor));
canvas.drawText(language, width / 2, baseline - descent, paint); canvas.drawText(language, width / 2, baseline - descent, paint);
// Put arrows that are already layed out on either side of the text // Put arrows that are already layed out on either side of the text
if (SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER if (SubtypeSwitcher.getInstance().useSpacebarLanguageSwitcher()
&& subtypeSwitcher.getEnabledKeyboardLocaleCount() > 1) { && subtypeSwitcher.getEnabledKeyboardLocaleCount() > 1) {
mButtonArrowLeftIcon.draw(canvas); mButtonArrowLeftIcon.draw(canvas);
mButtonArrowRightIcon.draw(canvas); mButtonArrowRightIcon.draw(canvas);
@ -291,7 +311,6 @@ public class LatinKeyboard extends Keyboard {
* switching input languages. * switching input languages.
*/ */
@Override @Override
@SuppressWarnings("unused") // SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER is constant
public boolean isInside(Key key, int pointX, int pointY) { public boolean isInside(Key key, int pointX, int pointY) {
int x = pointX; int x = pointX;
int y = pointY; int y = pointY;
@ -302,7 +321,7 @@ public class LatinKeyboard extends Keyboard {
if (code == CODE_DELETE) x -= key.mWidth / 6; if (code == CODE_DELETE) x -= key.mWidth / 6;
} else if (code == CODE_SPACE) { } else if (code == CODE_SPACE) {
y += LatinKeyboard.sSpacebarVerticalCorrection; y += LatinKeyboard.sSpacebarVerticalCorrection;
if (SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER if (SubtypeSwitcher.getInstance().useSpacebarLanguageSwitcher()
&& SubtypeSwitcher.getInstance().getEnabledKeyboardLocaleCount() > 1) { && SubtypeSwitcher.getInstance().getEnabledKeyboardLocaleCount() > 1) {
if (mCurrentlyInSpace) { if (mCurrentlyInSpace) {
int diff = x - mSpaceDragStartX; int diff = x - mSpaceDragStartX;

View File

@ -85,6 +85,14 @@ public class LatinKeyboardView extends KeyboardView {
} }
} }
public void setSpacebarTextFadeFactor(float fadeFactor, LatinKeyboard oldKeyboard) {
final LatinKeyboard currentKeyboard = getLatinKeyboard();
// We should not set text fade factor to the keyboard which does not display the language on
// its spacebar.
if (currentKeyboard != null && currentKeyboard == oldKeyboard)
currentKeyboard.setSpacebarTextFadeFactor(fadeFactor, this);
}
@Override @Override
protected boolean onLongPress(Key key) { protected boolean onLongPress(Key key) {
int primaryCode = key.mCode; int primaryCode = key.mCode;
@ -197,10 +205,10 @@ public class LatinKeyboardView extends KeyboardView {
@Override @Override
public boolean onTouchEvent(MotionEvent me) { public boolean onTouchEvent(MotionEvent me) {
LatinKeyboard keyboard = getLatinKeyboard(); LatinKeyboard keyboard = getLatinKeyboard();
if (keyboard == null) return true;
// If there was a sudden jump, return without processing the actual motion event. // If there was a sudden jump, return without processing the actual motion event.
if (handleSuddenJump(me)) if (handleSuddenJump(me)) return true;
return true;
// Reset any bounding box controls in the keyboard // Reset any bounding box controls in the keyboard
if (me.getAction() == MotionEvent.ACTION_DOWN) { if (me.getAction() == MotionEvent.ACTION_DOWN) {

View File

@ -71,7 +71,7 @@ public class MiniKeyboardBuilder {
for (CharSequence popupSpec : popupCharacters) { for (CharSequence popupSpec : popupCharacters) {
final CharSequence label = PopupCharactersParser.getLabel(popupSpec.toString()); final CharSequence label = PopupCharactersParser.getLabel(popupSpec.toString());
// If the label is single letter, minKeyWidth is enough to hold the label. // If the label is single letter, minKeyWidth is enough to hold the label.
if (label.length() > 1) { if (label != null && label.length() > 1) {
if (paint == null) { if (paint == null) {
paint = new Paint(); paint = new Paint();
paint.setAntiAlias(true); paint.setAntiAlias(true);

View File

@ -42,6 +42,7 @@ public class BinaryDictionary extends Dictionary {
private static final int TYPED_LETTER_MULTIPLIER = 2; private static final int TYPED_LETTER_MULTIPLIER = 2;
private static final BinaryDictionary sInstance = new BinaryDictionary();
private int mDicTypeId; private int mDicTypeId;
private int mNativeDict; private int mNativeDict;
private long mDictLength; private long mDictLength;
@ -59,16 +60,24 @@ public class BinaryDictionary extends Dictionary {
} }
} }
private BinaryDictionary() {
}
/** /**
* Create a dictionary from a raw resource file * Initialize a dictionary from a raw resource file
* @param context application context for reading resources * @param context application context for reading resources
* @param resId the resource containing the raw binary dictionary * @param resId the resource containing the raw binary dictionary
* @return initialized instance of BinaryDictionary
*/ */
public BinaryDictionary(Context context, int resId, int dicTypeId) { public static BinaryDictionary initDictionary(Context context, int resId, int dicTypeId) {
if (resId != 0) { synchronized (sInstance) {
loadDictionary(context, resId); sInstance.closeInternal();
if (resId != 0) {
sInstance.loadDictionary(context, resId);
sInstance.mDicTypeId = dicTypeId;
}
} }
mDicTypeId = dicTypeId; return sInstance;
} }
private native int openNative(String sourceDir, long dictOffset, long dictSize, private native int openNative(String sourceDir, long dictOffset, long dictSize,
@ -104,6 +113,8 @@ public class BinaryDictionary extends Dictionary {
@Override @Override
public void getBigrams(final WordComposer codes, final CharSequence previousWord, public void getBigrams(final WordComposer codes, final CharSequence previousWord,
final WordCallback callback, int[] nextLettersFrequencies) { final WordCallback callback, int[] nextLettersFrequencies) {
if (mNativeDict == 0) return;
char[] chars = previousWord.toString().toCharArray(); char[] chars = previousWord.toString().toCharArray();
Arrays.fill(mOutputChars_bigrams, (char) 0); Arrays.fill(mOutputChars_bigrams, (char) 0);
Arrays.fill(mFrequencies_bigrams, 0); Arrays.fill(mFrequencies_bigrams, 0);
@ -135,6 +146,8 @@ public class BinaryDictionary extends Dictionary {
@Override @Override
public void getWords(final WordComposer codes, final WordCallback callback, public void getWords(final WordComposer codes, final WordCallback callback,
int[] nextLettersFrequencies) { int[] nextLettersFrequencies) {
if (mNativeDict == 0) return;
final int codesSize = codes.size(); final int codesSize = codes.size();
// Won't deal with really long words. // Won't deal with really long words.
if (codesSize > MAX_WORD_LENGTH - 1) return; if (codesSize > MAX_WORD_LENGTH - 1) return;
@ -179,6 +192,10 @@ public class BinaryDictionary extends Dictionary {
@Override @Override
public synchronized void close() { public synchronized void close() {
closeInternal();
}
private void closeInternal() {
if (mNativeDict != 0) { if (mNativeDict != 0) {
closeNative(mNativeDict); closeNative(mNativeDict);
mNativeDict = 0; mNativeDict = 0;
@ -188,7 +205,10 @@ public class BinaryDictionary extends Dictionary {
@Override @Override
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
close(); try {
super.finalize(); closeInternal();
} finally {
super.finalize();
}
} }
} }

View File

@ -45,23 +45,22 @@ import android.widget.TextView;
import java.util.ArrayList; import java.util.ArrayList;
public class CandidateView extends LinearLayout implements OnClickListener, OnLongClickListener { public class CandidateView extends LinearLayout implements OnClickListener, OnLongClickListener {
private LatinIME mService;
private final ArrayList<View> mWords = new ArrayList<View>();
private final TextView mPreviewText; private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD);
private final PopupWindow mPreviewPopup; private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
private static final int MAX_SUGGESTIONS = 16; private static final int MAX_SUGGESTIONS = 16;
private final ArrayList<View> mWords = new ArrayList<View>();
private final boolean mConfigCandidateHighlightFontColorEnabled; private final boolean mConfigCandidateHighlightFontColorEnabled;
private final CharacterStyle mInvertedForegroundColorSpan;
private final CharacterStyle mInvertedBackgroundColorSpan;
private final int mColorNormal; private final int mColorNormal;
private final int mColorRecommended; private final int mColorRecommended;
private final int mColorOther; private final int mColorOther;
private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); private final PopupWindow mPreviewPopup;
private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); private final TextView mPreviewText;
private final CharacterStyle mInvertedForegroundColorSpan;
private final CharacterStyle mInvertedBackgroundColorSpan;
private LatinIME mService;
private SuggestedWords mSuggestions = SuggestedWords.EMPTY; private SuggestedWords mSuggestions = SuggestedWords.EMPTY;
private boolean mShowingAutoCorrectionInverted; private boolean mShowingAutoCorrectionInverted;
private boolean mShowingAddToDictionary; private boolean mShowingAddToDictionary;
@ -186,9 +185,10 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
final TextView tv = (TextView)v.findViewById(R.id.candidate_word); final TextView tv = (TextView)v.findViewById(R.id.candidate_word);
final TextView dv = (TextView)v.findViewById(R.id.candidate_debug_info); final TextView dv = (TextView)v.findViewById(R.id.candidate_debug_info);
tv.setTextColor(mColorNormal); tv.setTextColor(mColorNormal);
// TODO: Needs safety net?
if (suggestions.mHasMinimalSuggestion if (suggestions.mHasMinimalSuggestion
&& ((i == 1 && !suggestions.mTypedWordValid) || && ((i == 1 && !suggestions.mTypedWordValid)
(i == 0 && suggestions.mTypedWordValid))) { || (i == 0 && suggestions.mTypedWordValid))) {
final CharacterStyle style; final CharacterStyle style;
if (mConfigCandidateHighlightFontColorEnabled) { if (mConfigCandidateHighlightFontColorEnabled) {
style = BOLD_SPAN; style = BOLD_SPAN;
@ -329,7 +329,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
mService.pickSuggestionManually(index, word); mService.pickSuggestionManually(index, word);
} }
} }
@Override @Override
public void onDetachedFromWindow() { public void onDetachedFromWindow() {
super.onDetachedFromWindow(); super.onDetachedFromWindow();

View File

@ -107,7 +107,7 @@ public class InputLanguageSelection extends PreferenceActivity {
res.updateConfiguration(conf, res.getDisplayMetrics()); res.updateConfiguration(conf, res.getDisplayMetrics());
int mainDicResId = LatinIME.getMainDictionaryResourceId(res); int mainDicResId = LatinIME.getMainDictionaryResourceId(res);
BinaryDictionary bd = new BinaryDictionary(this, mainDicResId, Suggest.DIC_MAIN); BinaryDictionary bd = BinaryDictionary.initDictionary(this, mainDicResId, Suggest.DIC_MAIN);
// Is the dictionary larger than a placeholder? Arbitrarily chose a lower limit of // Is the dictionary larger than a placeholder? Arbitrarily chose a lower limit of
// 4000-5000 words, whereas the LARGE_DICTIONARY is about 20000+ words. // 4000-5000 words, whereas the LARGE_DICTIONARY is about 20000+ words.

View File

@ -22,6 +22,7 @@ import com.android.inputmethod.keyboard.KeyboardActionListener;
import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.keyboard.KeyboardView; import com.android.inputmethod.keyboard.KeyboardView;
import com.android.inputmethod.keyboard.LatinKeyboard;
import com.android.inputmethod.keyboard.LatinKeyboardView; import com.android.inputmethod.keyboard.LatinKeyboardView;
import com.android.inputmethod.latin.Utils.RingCharBuffer; import com.android.inputmethod.latin.Utils.RingCharBuffer;
import com.android.inputmethod.voice.VoiceIMEConnector; import com.android.inputmethod.voice.VoiceIMEConnector;
@ -132,14 +133,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private Resources mResources; private Resources mResources;
private SharedPreferences mPrefs; private SharedPreferences mPrefs;
// These variables are initialized according to the {@link EditorInfo#inputType}.
private boolean mAutoSpace;
private boolean mInputTypeNoAutoCorrect;
private boolean mIsSettingsSuggestionStripOn;
private boolean mApplicationSpecifiedCompletionOn;
private final StringBuilder mComposing = new StringBuilder(); private final StringBuilder mComposing = new StringBuilder();
private WordComposer mWord = new WordComposer(); private WordComposer mWord = new WordComposer();
private CharSequence mBestWord; private CharSequence mBestWord;
private boolean mHasValidSuggestions; private boolean mHasValidSuggestions;
private boolean mIsSettingsSuggestionStripOn;
private boolean mApplicationSpecifiedCompletionOn;
private boolean mHasDictionary; private boolean mHasDictionary;
private boolean mAutoSpace;
private boolean mJustAddedAutoSpace; private boolean mJustAddedAutoSpace;
private boolean mAutoCorrectEnabled; private boolean mAutoCorrectEnabled;
private boolean mReCorrectionEnabled; private boolean mReCorrectionEnabled;
@ -151,6 +155,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private boolean mAutoCap; private boolean mAutoCap;
private boolean mQuickFixes; private boolean mQuickFixes;
private boolean mConfigSwipeDownDismissKeyboardEnabled; private boolean mConfigSwipeDownDismissKeyboardEnabled;
private int mConfigDelayBeforeFadeoutLanguageOnSpacebar;
private int mConfigDurationOfFadeoutLanguageOnSpacebar;
private float mConfigFinalFadeoutFactorOfLanguageOnSpacebar;
private int mCorrectionMode; private int mCorrectionMode;
private int mCommittedLength; private int mCommittedLength;
@ -160,9 +167,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private int mLastSelectionEnd; private int mLastSelectionEnd;
private SuggestedWords mSuggestPuncList; private SuggestedWords mSuggestPuncList;
// Input type is such that we should not auto-correct
private boolean mInputTypeNoAutoCorrect;
// Indicates whether the suggestion strip is to be on in landscape // Indicates whether the suggestion strip is to be on in landscape
private boolean mJustAccepted; private boolean mJustAccepted;
private boolean mJustReverted; private boolean mJustReverted;
@ -241,9 +245,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private static final int MSG_UPDATE_OLD_SUGGESTIONS = 1; private static final int MSG_UPDATE_OLD_SUGGESTIONS = 1;
private static final int MSG_UPDATE_SHIFT_STATE = 2; private static final int MSG_UPDATE_SHIFT_STATE = 2;
private static final int MSG_VOICE_RESULTS = 3; private static final int MSG_VOICE_RESULTS = 3;
private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 4;
private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 5;
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
final KeyboardSwitcher switcher = mKeyboardSwitcher;
final LatinKeyboardView inputView = switcher.getInputView();
switch (msg.what) { switch (msg.what) {
case MSG_UPDATE_SUGGESTIONS: case MSG_UPDATE_SUGGESTIONS:
updateSuggestions(); updateSuggestions();
@ -252,12 +260,24 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
setOldSuggestions(); setOldSuggestions();
break; break;
case MSG_UPDATE_SHIFT_STATE: case MSG_UPDATE_SHIFT_STATE:
mKeyboardSwitcher.updateShiftState(); switcher.updateShiftState();
break; break;
case MSG_VOICE_RESULTS: case MSG_VOICE_RESULTS:
mVoiceConnector.handleVoiceResults(preferCapitalization() mVoiceConnector.handleVoiceResults(preferCapitalization()
|| (mKeyboardSwitcher.isAlphabetMode() || (switcher.isAlphabetMode() && switcher.isShiftedOrShiftLocked()));
&& mKeyboardSwitcher.isShiftedOrShiftLocked())); break;
case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR:
if (inputView != null)
inputView.setSpacebarTextFadeFactor(
(1.0f + mConfigFinalFadeoutFactorOfLanguageOnSpacebar) / 2,
(LatinKeyboard)msg.obj);
sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj),
mConfigDurationOfFadeoutLanguageOnSpacebar);
break;
case MSG_DISMISS_LANGUAGE_ON_SPACEBAR:
if (inputView != null)
inputView.setSpacebarTextFadeFactor(
mConfigFinalFadeoutFactorOfLanguageOnSpacebar, (LatinKeyboard)msg.obj);
break; break;
} }
} }
@ -297,6 +317,24 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
public void updateVoiceResults() { public void updateVoiceResults() {
sendMessage(obtainMessage(MSG_VOICE_RESULTS)); sendMessage(obtainMessage(MSG_VOICE_RESULTS));
} }
public void startDisplayLanguageOnSpacebar(boolean localeChanged) {
removeMessages(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR);
removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR);
final LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
if (inputView != null) {
final LatinKeyboard keyboard = inputView.getLatinKeyboard();
// The language is never displayed when the delay is zero.
if (mConfigDelayBeforeFadeoutLanguageOnSpacebar != 0)
inputView.setSpacebarTextFadeFactor(localeChanged ? 1.0f
: mConfigFinalFadeoutFactorOfLanguageOnSpacebar, keyboard);
// The language is always displayed when the delay is negative.
if (localeChanged && mConfigDelayBeforeFadeoutLanguageOnSpacebar > 0) {
sendMessageDelayed(obtainMessage(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR, keyboard),
mConfigDelayBeforeFadeoutLanguageOnSpacebar);
}
}
}
} }
@Override @Override
@ -315,10 +353,24 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final Resources res = getResources(); final Resources res = getResources();
mResources = res; mResources = res;
mReCorrectionEnabled = prefs.getBoolean(Settings.PREF_RECORRECTION_ENABLED,
res.getBoolean(R.bool.default_recorrection_enabled)); // If the option should not be shown, do not read the recorrection preference
// but always use the default setting defined in the resources.
if (res.getBoolean(R.bool.config_enable_show_recorrection_option)) {
mReCorrectionEnabled = prefs.getBoolean(Settings.PREF_RECORRECTION_ENABLED,
res.getBoolean(R.bool.default_recorrection_enabled));
} else {
mReCorrectionEnabled = res.getBoolean(R.bool.default_recorrection_enabled);
}
mConfigSwipeDownDismissKeyboardEnabled = res.getBoolean( mConfigSwipeDownDismissKeyboardEnabled = res.getBoolean(
R.bool.config_swipe_down_dismiss_keyboard_enabled); R.bool.config_swipe_down_dismiss_keyboard_enabled);
mConfigDelayBeforeFadeoutLanguageOnSpacebar = res.getInteger(
R.integer.config_delay_before_fadeout_language_on_spacebar);
mConfigDurationOfFadeoutLanguageOnSpacebar = res.getInteger(
R.integer.config_duration_of_fadeout_language_on_spacebar);
mConfigFinalFadeoutFactorOfLanguageOnSpacebar = res.getInteger(
R.integer.config_final_fadeout_percentage_of_language_on_spacebar) / 100.0f;
Utils.GCUtils.getInstance().reset(); Utils.GCUtils.getInstance().reset();
boolean tryGC = true; boolean tryGC = true;
@ -360,7 +412,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mSuggest.close(); mSuggest.close();
} }
final SharedPreferences prefs = mPrefs; final SharedPreferences prefs = mPrefs;
mQuickFixes = prefs.getBoolean(Settings.PREF_QUICK_FIXES, true); mQuickFixes = isQuickFixesEnabled(prefs);
final Resources res = mResources; final Resources res = mResources;
int mainDicResId = getMainDictionaryResourceId(res); int mainDicResId = getMainDictionaryResourceId(res);
@ -402,27 +454,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override @Override
public void onConfigurationChanged(Configuration conf) { public void onConfigurationChanged(Configuration conf) {
mSubtypeSwitcher.onConfigurationChanged(conf); mSubtypeSwitcher.onConfigurationChanged(conf);
if (mSubtypeSwitcher.isKeyboardMode())
onKeyboardLanguageChanged();
updateAutoTextEnabled();
// If orientation changed while predicting, commit the change // If orientation changed while predicting, commit the change
if (conf.orientation != mOrientation) { if (conf.orientation != mOrientation) {
InputConnection ic = getCurrentInputConnection(); InputConnection ic = getCurrentInputConnection();
commitTyped(ic); commitTyped(ic);
if (ic != null) ic.finishComposingText(); // For voice input if (ic != null) ic.finishComposingText(); // For voice input
mOrientation = conf.orientation; mOrientation = conf.orientation;
final int mode = mKeyboardSwitcher.getKeyboardMode();
final EditorInfo attribute = getCurrentInputEditorInfo();
final int imeOptions = (attribute != null) ? attribute.imeOptions : 0;
mKeyboardSwitcher.loadKeyboard(mode, imeOptions,
mVoiceConnector.isVoiceButtonEnabled(),
mVoiceConnector.isVoiceButtonOnPrimary());
} }
mConfigurationChanging = true; mConfigurationChanging = true;
super.onConfigurationChanged(conf); super.onConfigurationChanged(conf);
mVoiceConnector.onConfigurationChanged(mConfigurationChanging); mVoiceConnector.onConfigurationChanged(conf);
mConfigurationChanging = false; mConfigurationChanging = false;
} }
@ -473,24 +515,62 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (mRefreshKeyboardRequired) { if (mRefreshKeyboardRequired) {
mRefreshKeyboardRequired = false; mRefreshKeyboardRequired = false;
onKeyboardLanguageChanged(); onRefreshKeyboard();
} }
TextEntryState.newSession(this); TextEntryState.newSession(this);
// Most such things we decide below in the switch statement, but we need to know // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
// now whether this is a password text field, because we need to know now (before // know now whether this is a password text field, because we need to know now whether we
// the switch statement) whether we want to enable the voice button. // want to enable the voice button.
int variation = attribute.inputType & InputType.TYPE_MASK_VARIATION; mVoiceConnector.resetVoiceStates(isPasswordVariation(
mVoiceConnector.resetVoiceStates(isPasswordVariation(variation)); attribute.inputType & InputType.TYPE_MASK_VARIATION));
final int mode = initializeInputAttributesAndGetMode(attribute.inputType);
inputView.closing();
mEnteredText = null;
mComposing.setLength(0);
mHasValidSuggestions = false;
mDeleteCount = 0;
mJustAddedAutoSpace = false;
loadSettings(attribute);
if (mSubtypeSwitcher.isKeyboardMode()) {
switcher.loadKeyboard(mode, attribute.imeOptions,
mVoiceConnector.isVoiceButtonEnabled(),
mVoiceConnector.isVoiceButtonOnPrimary());
switcher.updateShiftState();
}
setCandidatesViewShownInternal(isCandidateStripVisible(),
false /* needsInputViewShown */ );
// Delay updating suggestions because keyboard input view may not be shown at this point.
mHandler.postUpdateSuggestions();
updateCorrectionMode();
inputView.setPreviewEnabled(mPopupOn);
inputView.setProximityCorrectionEnabled(true);
// If we just entered a text field, maybe it has some old text that requires correction
checkReCorrectionOnStart();
inputView.setForeground(true);
mVoiceConnector.onStartInputView(inputView.getWindowToken());
if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
}
private int initializeInputAttributesAndGetMode(int inputType) {
final int variation = inputType & InputType.TYPE_MASK_VARIATION;
mAutoSpace = false;
mInputTypeNoAutoCorrect = false; mInputTypeNoAutoCorrect = false;
mIsSettingsSuggestionStripOn = false; mIsSettingsSuggestionStripOn = false;
mApplicationSpecifiedCompletionOn = false; mApplicationSpecifiedCompletionOn = false;
mApplicationSpecifiedCompletions = null; mApplicationSpecifiedCompletions = null;
mEnteredText = null;
final int mode; final int mode;
switch (attribute.inputType & InputType.TYPE_MASK_CLASS) { switch (inputType & InputType.TYPE_MASK_CLASS) {
case InputType.TYPE_CLASS_NUMBER: case InputType.TYPE_CLASS_NUMBER:
case InputType.TYPE_CLASS_DATETIME: case InputType.TYPE_CLASS_DATETIME:
mode = KeyboardId.MODE_NUMBER; mode = KeyboardId.MODE_NUMBER;
@ -525,7 +605,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mode = KeyboardId.MODE_WEB; mode = KeyboardId.MODE_WEB;
// If it's a browser edit field and auto correct is not ON explicitly, then // If it's a browser edit field and auto correct is not ON explicitly, then
// disable auto correction, but keep suggestions on. // disable auto correction, but keep suggestions on.
if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) { if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
mInputTypeNoAutoCorrect = true; mInputTypeNoAutoCorrect = true;
} }
} else { } else {
@ -533,16 +613,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} }
// If NO_SUGGESTIONS is set, don't do prediction. // If NO_SUGGESTIONS is set, don't do prediction.
if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) { if ((inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
mIsSettingsSuggestionStripOn = false; mIsSettingsSuggestionStripOn = false;
mInputTypeNoAutoCorrect = true; mInputTypeNoAutoCorrect = true;
} }
// If it's not multiline and the autoCorrect flag is not set, then don't correct // If it's not multiline and the autoCorrect flag is not set, then don't correct
if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 && if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 &&
(attribute.inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) { (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
mInputTypeNoAutoCorrect = true; mInputTypeNoAutoCorrect = true;
} }
if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) { if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
mIsSettingsSuggestionStripOn = false; mIsSettingsSuggestionStripOn = false;
mApplicationSpecifiedCompletionOn = isFullscreenMode(); mApplicationSpecifiedCompletionOn = isFullscreenMode();
} }
@ -551,40 +631,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mode = KeyboardId.MODE_TEXT; mode = KeyboardId.MODE_TEXT;
break; break;
} }
inputView.closing(); return mode;
mComposing.setLength(0);
mHasValidSuggestions = false;
mDeleteCount = 0;
mJustAddedAutoSpace = false;
loadSettings(attribute);
if (mSubtypeSwitcher.isKeyboardMode()) {
switcher.loadKeyboard(mode, attribute.imeOptions,
mVoiceConnector.isVoiceButtonEnabled(),
mVoiceConnector.isVoiceButtonOnPrimary());
switcher.updateShiftState();
}
setCandidatesViewShownInternal(isCandidateStripVisible(),
false /* needsInputViewShown */ );
// Delay updating suggestions because keyboard input view may not be shown at this point.
mHandler.postUpdateSuggestions();
// If the dictionary is not big enough, don't auto correct
mHasDictionary = mSuggest.hasMainDictionary();
updateCorrectionMode();
inputView.setPreviewEnabled(mPopupOn);
inputView.setProximityCorrectionEnabled(true);
mIsSettingsSuggestionStripOn &= (mCorrectionMode > 0 || isShowingSuggestionsStrip());
// If we just entered a text field, maybe it has some old text that requires correction
checkReCorrectionOnStart();
inputView.setForeground(true);
mVoiceConnector.onStartInputView(mKeyboardSwitcher.getInputView().getWindowToken());
if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
} }
private void checkReCorrectionOnStart() { private void checkReCorrectionOnStart() {
@ -1106,14 +1153,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private void handleBackspace() { private void handleBackspace() {
if (mVoiceConnector.logAndRevertVoiceInput()) return; if (mVoiceConnector.logAndRevertVoiceInput()) return;
boolean deleteChar = false;
InputConnection ic = getCurrentInputConnection();
if (ic == null) return;
final InputConnection ic = getCurrentInputConnection();
if (ic == null) return;
ic.beginBatchEdit(); ic.beginBatchEdit();
mVoiceConnector.handleBackspace(); mVoiceConnector.handleBackspace();
boolean deleteChar = false;
if (mHasValidSuggestions) { if (mHasValidSuggestions) {
final int length = mComposing.length(); final int length = mComposing.length();
if (length > 0) { if (length > 0) {
@ -1131,12 +1178,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
deleteChar = true; deleteChar = true;
} }
mHandler.postUpdateShiftKeyState(); mHandler.postUpdateShiftKeyState();
TextEntryState.backspace(); TextEntryState.backspace();
if (TextEntryState.getState() == TextEntryState.State.UNDO_COMMIT) { if (TextEntryState.getState() == TextEntryState.State.UNDO_COMMIT) {
revertLastWord(deleteChar); revertLastWord(deleteChar);
ic.endBatchEdit(); ic.endBatchEdit();
return; return;
} else if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) { }
if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) {
ic.deleteSurroundingText(mEnteredText.length(), 0); ic.deleteSurroundingText(mEnteredText.length(), 0);
} else if (deleteChar) { } else if (deleteChar) {
if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) { if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
@ -1355,7 +1405,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} }
private boolean isSuggestionsRequested() { private boolean isSuggestionsRequested() {
return mIsSettingsSuggestionStripOn; return mIsSettingsSuggestionStripOn
&& (mCorrectionMode > 0 || isShowingSuggestionsStrip());
} }
private boolean isShowingPunctuationList() { private boolean isShowingPunctuationList() {
@ -1491,7 +1542,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) { private void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) {
setSuggestions(suggestedWords); setSuggestions(suggestedWords);
if (suggestedWords.size() > 0) { if (suggestedWords.size() > 0) {
if (suggestedWords.hasAutoCorrectionWord()) { if (Utils.shouldBlockedBySafetyNetForAutoCorrection(suggestedWords)) {
mBestWord = typedWord;
} else if (suggestedWords.hasAutoCorrectionWord()) {
mBestWord = suggestedWords.getWord(1); mBestWord = suggestedWords.getWord(1);
} else { } else {
mBestWord = typedWord; mBestWord = typedWord;
@ -1773,18 +1826,31 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final int length = mComposing.length(); final int length = mComposing.length();
if (!mHasValidSuggestions && length > 0) { if (!mHasValidSuggestions && length > 0) {
final InputConnection ic = getCurrentInputConnection(); final InputConnection ic = getCurrentInputConnection();
mHasValidSuggestions = true;
mJustReverted = true; mJustReverted = true;
final CharSequence punctuation = ic.getTextBeforeCursor(1, 0);
if (deleteChar) ic.deleteSurroundingText(1, 0); if (deleteChar) ic.deleteSurroundingText(1, 0);
int toDelete = mCommittedLength; int toDelete = mCommittedLength;
CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0); final CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0);
if (toTheLeft != null && toTheLeft.length() > 0 if (!TextUtils.isEmpty(toTheLeft) && isWordSeparator(toTheLeft.charAt(0))) {
&& isWordSeparator(toTheLeft.charAt(0))) {
toDelete--; toDelete--;
} }
ic.deleteSurroundingText(toDelete, 0); ic.deleteSurroundingText(toDelete, 0);
ic.setComposingText(mComposing, 1); // Re-insert punctuation only when the deleted character was word separator and the
TextEntryState.backspace(); // composing text wasn't equal to the auto-corrected text.
if (deleteChar
&& !TextUtils.isEmpty(punctuation) && isWordSeparator(punctuation.charAt(0))
&& !TextUtils.equals(mComposing, toTheLeft)) {
ic.commitText(mComposing, 1);
TextEntryState.acceptedTyped(mComposing);
ic.commitText(punctuation, 1);
TextEntryState.typedCharacter(punctuation.charAt(0), true);
// Clear composing text
mComposing.setLength(0);
} else {
mHasValidSuggestions = true;
ic.setComposingText(mComposing, 1);
TextEntryState.backspace();
}
mHandler.postUpdateSuggestions(); mHandler.postUpdateSuggestions();
} else { } else {
sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
@ -1814,21 +1880,22 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return mWord.isFirstCharCapitalized(); return mWord.isFirstCharCapitalized();
} }
// Notify that Language has been changed and toggleLanguage will update KeyboaredID according // Notify that language or mode have been changed and toggleLanguage will update KeyboaredID
// to new Language. // according to new language or mode.
public void onKeyboardLanguageChanged() { public void onRefreshKeyboard() {
toggleLanguage(true, true); toggleLanguage(true, true);
} }
// "reset" and "next" are used only for USE_SPACEBAR_LANGUAGE_SWITCHER. // "reset" and "next" are used only for USE_SPACEBAR_LANGUAGE_SWITCHER.
private void toggleLanguage(boolean reset, boolean next) { private void toggleLanguage(boolean reset, boolean next) {
if (SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER) { if (mSubtypeSwitcher.useSpacebarLanguageSwitcher()) {
mSubtypeSwitcher.toggleLanguage(reset, next); mSubtypeSwitcher.toggleLanguage(reset, next);
} }
// Reload keyboard because the current language has been changed. // Reload keyboard because the current language has been changed.
KeyboardSwitcher switcher = mKeyboardSwitcher; KeyboardSwitcher switcher = mKeyboardSwitcher;
final int mode = switcher.getKeyboardMode();
final EditorInfo attribute = getCurrentInputEditorInfo(); final EditorInfo attribute = getCurrentInputEditorInfo();
final int mode = initializeInputAttributesAndGetMode((attribute != null)
? attribute.inputType : 0);
final int imeOptions = (attribute != null) ? attribute.imeOptions : 0; final int imeOptions = (attribute != null) ? attribute.imeOptions : 0;
switcher.loadKeyboard(mode, imeOptions, mVoiceConnector.isVoiceButtonEnabled(), switcher.loadKeyboard(mode, imeOptions, mVoiceConnector.isVoiceButtonEnabled(),
mVoiceConnector.isVoiceButtonOnPrimary()); mVoiceConnector.isVoiceButtonOnPrimary());
@ -2016,7 +2083,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mPopupOn = prefs.getBoolean(Settings.PREF_POPUP_ON, mPopupOn = prefs.getBoolean(Settings.PREF_POPUP_ON,
mResources.getBoolean(R.bool.config_default_popup_preview)); mResources.getBoolean(R.bool.config_default_popup_preview));
mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true); mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true);
mQuickFixes = prefs.getBoolean(Settings.PREF_QUICK_FIXES, true); mQuickFixes = isQuickFixesEnabled(prefs);
mAutoCorrectEnabled = isAutoCorrectEnabled(prefs); mAutoCorrectEnabled = isAutoCorrectEnabled(prefs);
mBigramSuggestionEnabled = mAutoCorrectEnabled && isBigramSuggestionEnabled(prefs); mBigramSuggestionEnabled = mAutoCorrectEnabled && isBigramSuggestionEnabled(prefs);
@ -2065,6 +2132,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mSuggest.setAutoCorrectionThreshold(autoCorrectionThreshold); mSuggest.setAutoCorrectionThreshold(autoCorrectionThreshold);
} }
private boolean isQuickFixesEnabled(SharedPreferences sp) {
final boolean showQuickFixesOption = mResources.getBoolean(
R.bool.config_enable_quick_fixes_option);
if (!showQuickFixesOption) {
return isAutoCorrectEnabled(sp);
}
return sp.getBoolean(Settings.PREF_QUICK_FIXES, mResources.getBoolean(
R.bool.config_default_quick_fixes));
}
private boolean isAutoCorrectEnabled(SharedPreferences sp) { private boolean isAutoCorrectEnabled(SharedPreferences sp) {
final String currentAutoCorrectionSetting = sp.getString( final String currentAutoCorrectionSetting = sp.getString(
Settings.PREF_AUTO_CORRECTION_THRESHOLD, Settings.PREF_AUTO_CORRECTION_THRESHOLD,
@ -2075,8 +2152,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} }
private boolean isBigramSuggestionEnabled(SharedPreferences sp) { private boolean isBigramSuggestionEnabled(SharedPreferences sp) {
// TODO: Define default value instead of 'true'. final boolean showBigramSuggestionsOption = mResources.getBoolean(
return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, true); R.bool.config_enable_bigram_suggestions_option);
if (!showBigramSuggestionsOption) {
return isAutoCorrectEnabled(sp);
}
return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, mResources.getBoolean(
R.bool.config_default_bigram_suggestions));
} }
private void initSuggestPuncList() { private void initSuggestPuncList() {

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2008 The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * 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 * use this file except in compliance with the License. You may obtain a copy of
* the License at * the License at
@ -48,6 +48,7 @@ public class Settings extends PreferenceActivity
DialogInterface.OnDismissListener, OnPreferenceClickListener { DialogInterface.OnDismissListener, OnPreferenceClickListener {
private static final String TAG = "Settings"; private static final String TAG = "Settings";
public static final String PREF_GENERAL_SETTINGS_KEY = "general_settings";
public static final String PREF_VIBRATE_ON = "vibrate_on"; public static final String PREF_VIBRATE_ON = "vibrate_on";
public static final String PREF_SOUND_ON = "sound_on"; public static final String PREF_SOUND_ON = "sound_on";
public static final String PREF_POPUP_ON = "popup_on"; public static final String PREF_POPUP_ON = "popup_on";
@ -65,6 +66,8 @@ public class Settings extends PreferenceActivity
public static final String PREF_AUTO_CORRECTION_THRESHOLD = "auto_correction_threshold"; public static final String PREF_AUTO_CORRECTION_THRESHOLD = "auto_correction_threshold";
public static final String PREF_BIGRAM_SUGGESTIONS = "bigram_suggestion"; public static final String PREF_BIGRAM_SUGGESTIONS = "bigram_suggestion";
public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode";
// Dialog ids // Dialog ids
private static final int VOICE_INPUT_CONFIRM_DIALOG = 0; private static final int VOICE_INPUT_CONFIRM_DIALOG = 0;
@ -111,30 +114,64 @@ public class Settings extends PreferenceActivity
mBigramSuggestion = (CheckBoxPreference) findPreference(PREF_BIGRAM_SUGGESTIONS); mBigramSuggestion = (CheckBoxPreference) findPreference(PREF_BIGRAM_SUGGESTIONS);
ensureConsistencyOfAutoCorrectionSettings(); ensureConsistencyOfAutoCorrectionSettings();
final PreferenceGroup generalSettings =
(PreferenceGroup) findPreference(PREF_GENERAL_SETTINGS_KEY);
final PreferenceGroup textCorrectionGroup =
(PreferenceGroup) findPreference(PREF_PREDICTION_SETTINGS_KEY);
final boolean showSettingsKeyOption = getResources().getBoolean( final boolean showSettingsKeyOption = getResources().getBoolean(
R.bool.config_enable_show_settings_key_option); R.bool.config_enable_show_settings_key_option);
if (!showSettingsKeyOption) { if (!showSettingsKeyOption) {
getPreferenceScreen().removePreference(mSettingsKeyPreference); generalSettings.removePreference(mSettingsKeyPreference);
} }
final boolean showVoiceKeyOption = getResources().getBoolean( final boolean showVoiceKeyOption = getResources().getBoolean(
R.bool.config_enable_show_voice_key_option); R.bool.config_enable_show_voice_key_option);
if (!showVoiceKeyOption) { if (!showVoiceKeyOption) {
getPreferenceScreen().removePreference(mVoicePreference); generalSettings.removePreference(mVoicePreference);
} }
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE); Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
if (vibrator == null if (vibrator == null
// @@@ || !vibrator.hasVibrator() // @@@ || !vibrator.hasVibrator()
) { ) {
getPreferenceScreen().removePreference( generalSettings.removePreference(findPreference(PREF_VIBRATE_ON));
getPreferenceScreen().findPreference(PREF_VIBRATE_ON));
} }
final boolean showSubtypeSettings = getResources().getBoolean( final boolean showSubtypeSettings = getResources().getBoolean(
R.bool.config_enable_show_subtype_settings); R.bool.config_enable_show_subtype_settings);
if (!showSubtypeSettings) { if (!showSubtypeSettings) {
getPreferenceScreen().removePreference(findPreference(PREF_SUBTYPES)); generalSettings.removePreference(findPreference(PREF_SUBTYPES));
}
final boolean showPopupOption = getResources().getBoolean(
R.bool.config_enable_show_popup_on_keypress_option);
if (!showPopupOption) {
generalSettings.removePreference(findPreference(PREF_POPUP_ON));
}
final boolean showRecorrectionOption = getResources().getBoolean(
R.bool.config_enable_show_recorrection_option);
if (!showRecorrectionOption) {
generalSettings.removePreference(findPreference(PREF_RECORRECTION_ENABLED));
}
final boolean showQuickFixesOption = getResources().getBoolean(
R.bool.config_enable_quick_fixes_option);
if (!showQuickFixesOption) {
textCorrectionGroup.removePreference(findPreference(PREF_QUICK_FIXES));
}
final boolean showBigramSuggestionsOption = getResources().getBoolean(
R.bool.config_enable_bigram_suggestions_option);
if (!showBigramSuggestionsOption) {
textCorrectionGroup.removePreference(findPreference(PREF_BIGRAM_SUGGESTIONS));
}
final boolean showUsabilityModeStudyOption = getResources().getBoolean(
R.bool.config_enable_usability_study_mode_option);
if (!showUsabilityModeStudyOption) {
getPreferenceScreen().removePreference(findPreference(PREF_USABILITY_STUDY_MODE));
} }
} }
@ -184,7 +221,7 @@ public class Settings extends PreferenceActivity
if (pref == mInputLanguageSelection) { if (pref == mInputLanguageSelection) {
final String action; final String action;
if (android.os.Build.VERSION.SDK_INT if (android.os.Build.VERSION.SDK_INT
>= /* android.os.Build.VERSION_CODES.HONEYCOMB */ 10) { >= /* android.os.Build.VERSION_CODES.HONEYCOMB */ 11) {
action = "android.settings.INPUT_METHOD_AND_SUBTYPE_ENABLER"; action = "android.settings.INPUT_METHOD_AND_SUBTYPE_ENABLER";
} else { } else {
action = "com.android.inputmethod.latin.INPUT_LANGUAGE_SELECTION"; action = "com.android.inputmethod.latin.INPUT_LANGUAGE_SELECTION";

View File

@ -0,0 +1,46 @@
/*
* 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.latin;
import android.content.Context;
import android.content.res.Resources;
import java.util.Locale;
public class SubtypeLocale {
private static String[] sExceptionKeys;
private static String[] sExceptionValues;
private SubtypeLocale() {
// Intentional empty constructor for utility class.
}
public static void init(Context context) {
final Resources res = context.getResources();
sExceptionKeys = res.getStringArray(R.array.subtype_locale_exception_keys);
sExceptionValues = res.getStringArray(R.array.subtype_locale_exception_values);
}
public static String getFullDisplayName(Locale locale) {
String localeCode = locale.toString();
for (int index = 0; index < sExceptionKeys.length; index++) {
if (sExceptionKeys[index].equals(localeCode))
return sExceptionValues[index];
}
return locale.getDisplayName(locale);
}
}

View File

@ -16,6 +16,7 @@
package com.android.inputmethod.latin; package com.android.inputmethod.latin;
import com.android.inputmethod.compat.InputMethodSubtype;
import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.voice.SettingsUtil; import com.android.inputmethod.voice.SettingsUtil;
import com.android.inputmethod.voice.VoiceIMEConnector; import com.android.inputmethod.voice.VoiceIMEConnector;
@ -40,11 +41,6 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
public class SubtypeSwitcher { public class SubtypeSwitcher {
// TODO: This should be configurable by resource
// This flag indicates if we support language switching by swipe on space bar.
// We may or may not draw the current language on space bar regardless of this flag.
// @@@
public static final boolean USE_SPACEBAR_LANGUAGE_SWITCHER = true;
private static final boolean DBG = false; private static final boolean DBG = false;
private static final String TAG = "SubtypeSwitcher"; private static final String TAG = "SubtypeSwitcher";
@ -63,6 +59,8 @@ public class SubtypeSwitcher {
new ArrayList<InputMethodSubtype>(); new ArrayList<InputMethodSubtype>();
private final ArrayList<String> mEnabledLanguagesOfCurrentInputMethod = new ArrayList<String>(); private final ArrayList<String> mEnabledLanguagesOfCurrentInputMethod = new ArrayList<String>();
private boolean mConfigUseSpacebarLanguageSwitcher;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
// Variants which should be changed only by reload functions. // Variants which should be changed only by reload functions.
private boolean mNeedsToDisplayLanguage; private boolean mNeedsToDisplayLanguage;
@ -84,11 +82,9 @@ public class SubtypeSwitcher {
public static void init(LatinIME service, SharedPreferences prefs) { public static void init(LatinIME service, SharedPreferences prefs) {
sInstance.mPrefs = prefs; sInstance.mPrefs = prefs;
sInstance.resetParams(service); sInstance.resetParams(service);
if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
sInstance.initLanguageSwitcher(service);
}
sInstance.updateAllParameters(); sInstance.updateAllParameters();
SubtypeLocale.init(service);
} }
private SubtypeSwitcher() { private SubtypeSwitcher() {
@ -109,6 +105,10 @@ public class SubtypeSwitcher {
mAllEnabledSubtypesOfCurrentInputMethod = null; mAllEnabledSubtypesOfCurrentInputMethod = null;
// TODO: Voice input should be created here // TODO: Voice input should be created here
mVoiceInput = null; mVoiceInput = null;
mConfigUseSpacebarLanguageSwitcher = mResources.getBoolean(
R.bool.config_use_spacebar_language_switcher);
if (mConfigUseSpacebarLanguageSwitcher)
initLanguageSwitcher(service);
} }
// Update all parameters stored in SubtypeSwitcher. // Update all parameters stored in SubtypeSwitcher.
@ -122,8 +122,8 @@ public class SubtypeSwitcher {
// Update parameters which are changed outside LatinIME. This parameters affect UI so they // Update parameters which are changed outside LatinIME. This parameters affect UI so they
// should be updated every time onStartInputview. // should be updated every time onStartInputview.
public void updateParametersOnStartInputView() { public void updateParametersOnStartInputView() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) { if (mConfigUseSpacebarLanguageSwitcher) {
updateForSpaceBarLanguageSwitch(); updateForSpacebarLanguageSwitch();
} else { } else {
updateEnabledSubtypes(); updateEnabledSubtypes();
} }
@ -134,7 +134,7 @@ public class SubtypeSwitcher {
private void updateEnabledSubtypes() { private void updateEnabledSubtypes() {
boolean foundCurrentSubtypeBecameDisabled = true; boolean foundCurrentSubtypeBecameDisabled = true;
// @@@ mAllEnabledSubtypesOfCurrentInputMethod = mImm.getEnabledInputMethodSubtypeList( // @@@ mAllEnabledSubtypesOfCurrentInputMethod = mImm.getEnabledInputMethodSubtypeList(
//null, false); // null, true);
mEnabledLanguagesOfCurrentInputMethod.clear(); mEnabledLanguagesOfCurrentInputMethod.clear();
mEnabledKeyboardSubtypesOfCurrentInputMethod.clear(); mEnabledKeyboardSubtypesOfCurrentInputMethod.clear();
for (InputMethodSubtype ims: mAllEnabledSubtypesOfCurrentInputMethod) { for (InputMethodSubtype ims: mAllEnabledSubtypesOfCurrentInputMethod) {
@ -155,6 +155,7 @@ public class SubtypeSwitcher {
&& mIsSystemLanguageSameAsInputLanguage); && mIsSystemLanguageSameAsInputLanguage);
if (foundCurrentSubtypeBecameDisabled) { if (foundCurrentSubtypeBecameDisabled) {
if (DBG) { if (DBG) {
Log.w(TAG, "Current subtype: " + mInputLocaleStr + ", " + mMode);
Log.w(TAG, "Last subtype was disabled. Update to the current one."); Log.w(TAG, "Last subtype was disabled. Update to the current one.");
} }
// @@@ updateSubtype(mImm.getCurrentInputMethodSubtype()); // @@@ updateSubtype(mImm.getCurrentInputMethodSubtype());
@ -188,7 +189,7 @@ public class SubtypeSwitcher {
// fallback to the default locale and mode. // fallback to the default locale and mode.
Log.w(TAG, "Couldn't get the current subtype."); Log.w(TAG, "Couldn't get the current subtype.");
newLocale = "en_US"; newLocale = "en_US";
newMode =KEYBOARD_MODE; newMode = KEYBOARD_MODE;
} else { } else {
newLocale = newSubtype.getLocale(); newLocale = newSubtype.getLocale();
newMode = newSubtype.getMode(); newMode = newSubtype.getMode();
@ -218,8 +219,8 @@ public class SubtypeSwitcher {
mVoiceInput.cancel(); mVoiceInput.cancel();
} }
} }
if (languageChanged) { if (modeChanged || languageChanged) {
mService.onKeyboardLanguageChanged(); mService.onRefreshKeyboard();
} }
} else if (isVoiceMode()) { } else if (isVoiceMode()) {
// If needsToShowWarningDialog is true, voice input need to show warning before // If needsToShowWarningDialog is true, voice input need to show warning before
@ -311,19 +312,23 @@ public class SubtypeSwitcher {
////////////////////////////////// //////////////////////////////////
public int getEnabledKeyboardLocaleCount() { public int getEnabledKeyboardLocaleCount() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) { if (mConfigUseSpacebarLanguageSwitcher) {
return mLanguageSwitcher.getLocaleCount(); return mLanguageSwitcher.getLocaleCount();
} else { } else {
return mEnabledKeyboardSubtypesOfCurrentInputMethod.size(); return mEnabledKeyboardSubtypesOfCurrentInputMethod.size();
} }
} }
public boolean useSpacebarLanguageSwitcher() {
return mConfigUseSpacebarLanguageSwitcher;
}
public boolean needsToDisplayLanguage() { public boolean needsToDisplayLanguage() {
return mNeedsToDisplayLanguage; return mNeedsToDisplayLanguage;
} }
public Locale getInputLocale() { public Locale getInputLocale() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) { if (mConfigUseSpacebarLanguageSwitcher) {
return mLanguageSwitcher.getInputLocale(); return mLanguageSwitcher.getInputLocale();
} else { } else {
return mInputLocale; return mInputLocale;
@ -331,7 +336,7 @@ public class SubtypeSwitcher {
} }
public String getInputLocaleStr() { public String getInputLocaleStr() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) { if (mConfigUseSpacebarLanguageSwitcher) {
String inputLanguage = null; String inputLanguage = null;
inputLanguage = mLanguageSwitcher.getInputLanguage(); inputLanguage = mLanguageSwitcher.getInputLanguage();
// Should return system locale if there is no Language available. // Should return system locale if there is no Language available.
@ -345,7 +350,7 @@ public class SubtypeSwitcher {
} }
public String[] getEnabledLanguages() { public String[] getEnabledLanguages() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) { if (mConfigUseSpacebarLanguageSwitcher) {
return mLanguageSwitcher.getEnabledLanguages(); return mLanguageSwitcher.getEnabledLanguages();
} else { } else {
return mEnabledLanguagesOfCurrentInputMethod.toArray( return mEnabledLanguagesOfCurrentInputMethod.toArray(
@ -354,7 +359,7 @@ public class SubtypeSwitcher {
} }
public Locale getSystemLocale() { public Locale getSystemLocale() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) { if (mConfigUseSpacebarLanguageSwitcher) {
return mLanguageSwitcher.getSystemLocale(); return mLanguageSwitcher.getSystemLocale();
} else { } else {
return mSystemLocale; return mSystemLocale;
@ -362,7 +367,7 @@ public class SubtypeSwitcher {
} }
public boolean isSystemLanguageSameAsInputLanguage() { public boolean isSystemLanguageSameAsInputLanguage() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) { if (mConfigUseSpacebarLanguageSwitcher) {
return getSystemLocale().getLanguage().equalsIgnoreCase( return getSystemLocale().getLanguage().equalsIgnoreCase(
getInputLocaleStr().substring(0, 2)); getInputLocaleStr().substring(0, 2));
} else { } else {
@ -374,7 +379,7 @@ public class SubtypeSwitcher {
final Locale systemLocale = conf.locale; final Locale systemLocale = conf.locale;
// If system configuration was changed, update all parameters. // If system configuration was changed, update all parameters.
if (!TextUtils.equals(systemLocale.toString(), mSystemLocale.toString())) { if (!TextUtils.equals(systemLocale.toString(), mSystemLocale.toString())) {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) { if (mConfigUseSpacebarLanguageSwitcher) {
// If the system locale changes and is different from the saved // If the system locale changes and is different from the saved
// locale (mSystemLocale), then reload the input locale list from the // locale (mSystemLocale), then reload the input locale list from the
// latin ime settings (shared prefs) and reset the input locale // latin ime settings (shared prefs) and reset the input locale
@ -388,7 +393,7 @@ public class SubtypeSwitcher {
} }
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) { if (mConfigUseSpacebarLanguageSwitcher) {
if (Settings.PREF_SELECTED_LANGUAGES.equals(key)) { if (Settings.PREF_SELECTED_LANGUAGES.equals(key)) {
mLanguageSwitcher.loadLocales(sharedPreferences); mLanguageSwitcher.loadLocales(sharedPreferences);
} }
@ -438,18 +443,18 @@ public class SubtypeSwitcher {
private void triggerVoiceIME() { private void triggerVoiceIME() {
if (!mService.isInputViewShown()) return; if (!mService.isInputViewShown()) return;
VoiceIMEConnector.getInstance().startListening(false, VoiceIMEConnector.getInstance().startListening(false,
KeyboardSwitcher.getInstance().getInputView().getWindowToken(), false); KeyboardSwitcher.getInstance().getInputView().getWindowToken());
} }
////////////////////////////////////// //////////////////////////////////////
// SpaceBar Language Switch support // // Spacebar Language Switch support //
////////////////////////////////////// //////////////////////////////////////
private LanguageSwitcher mLanguageSwitcher; private LanguageSwitcher mLanguageSwitcher;
public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) { public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) {
if (returnsNameInThisLocale) { if (returnsNameInThisLocale) {
return toTitleCase(locale.getDisplayName(locale)); return toTitleCase(SubtypeLocale.getFullDisplayName(locale));
} else { } else {
return toTitleCase(locale.getDisplayName()); return toTitleCase(locale.getDisplayName());
} }
@ -470,7 +475,7 @@ public class SubtypeSwitcher {
return Character.toUpperCase(s.charAt(0)) + s.substring(1); return Character.toUpperCase(s.charAt(0)) + s.substring(1);
} }
private void updateForSpaceBarLanguageSwitch() { private void updateForSpacebarLanguageSwitch() {
// We need to update mNeedsToDisplayLanguage in onStartInputView because // We need to update mNeedsToDisplayLanguage in onStartInputView because
// getEnabledKeyboardLocaleCount could have been changed. // getEnabledKeyboardLocaleCount could have been changed.
mNeedsToDisplayLanguage = !(getEnabledKeyboardLocaleCount() <= 1 mNeedsToDisplayLanguage = !(getEnabledKeyboardLocaleCount() <= 1
@ -483,7 +488,7 @@ public class SubtypeSwitcher {
} }
public String getNextInputLanguageName() { public String getNextInputLanguageName() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) { if (mConfigUseSpacebarLanguageSwitcher) {
return getDisplayLanguage(mLanguageSwitcher.getNextInputLocale()); return getDisplayLanguage(mLanguageSwitcher.getNextInputLocale());
} else { } else {
return ""; return "";
@ -491,7 +496,7 @@ public class SubtypeSwitcher {
} }
public String getPreviousInputLanguageName() { public String getPreviousInputLanguageName() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) { if (mConfigUseSpacebarLanguageSwitcher) {
return getDisplayLanguage(mLanguageSwitcher.getPrevInputLocale()); return getDisplayLanguage(mLanguageSwitcher.getPrevInputLocale());
} else { } else {
return ""; return "";
@ -528,13 +533,13 @@ public class SubtypeSwitcher {
} }
public void loadSettings() { public void loadSettings() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) { if (mConfigUseSpacebarLanguageSwitcher) {
mLanguageSwitcher.loadLocales(mPrefs); mLanguageSwitcher.loadLocales(mPrefs);
} }
} }
public void toggleLanguage(boolean reset, boolean next) { public void toggleLanguage(boolean reset, boolean next) {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) { if (mConfigUseSpacebarLanguageSwitcher) {
if (reset) { if (reset) {
mLanguageSwitcher.reset(); mLanguageSwitcher.reset();
} else { } else {

View File

@ -31,7 +31,7 @@ import java.util.Arrays;
*/ */
public class Suggest implements Dictionary.WordCallback { public class Suggest implements Dictionary.WordCallback {
public static final String TAG = "Suggest"; public static final String TAG = Suggest.class.getSimpleName();
public static final int APPROX_MAX_WORD_LENGTH = 32; public static final int APPROX_MAX_WORD_LENGTH = 32;
@ -64,6 +64,8 @@ public class Suggest implements Dictionary.WordCallback {
static final int LARGE_DICTIONARY_THRESHOLD = 200 * 1000; static final int LARGE_DICTIONARY_THRESHOLD = 200 * 1000;
private static boolean DBG = LatinImeLogger.sDBG;
private BinaryDictionary mMainDict; private BinaryDictionary mMainDict;
private Dictionary mUserDictionary; private Dictionary mUserDictionary;
@ -93,7 +95,7 @@ public class Suggest implements Dictionary.WordCallback {
private ArrayList<CharSequence> mSuggestions = new ArrayList<CharSequence>(); private ArrayList<CharSequence> mSuggestions = new ArrayList<CharSequence>();
ArrayList<CharSequence> mBigramSuggestions = new ArrayList<CharSequence>(); ArrayList<CharSequence> mBigramSuggestions = new ArrayList<CharSequence>();
private ArrayList<CharSequence> mStringPool = new ArrayList<CharSequence>(); private ArrayList<CharSequence> mStringPool = new ArrayList<CharSequence>();
private boolean mHaveCorrection; private boolean mHaveAutoCorrection;
private String mLowerOriginalWord; private String mLowerOriginalWord;
// TODO: Remove these member variables by passing more context to addWord() callback method // TODO: Remove these member variables by passing more context to addWord() callback method
@ -103,7 +105,7 @@ public class Suggest implements Dictionary.WordCallback {
private int mCorrectionMode = CORRECTION_BASIC; private int mCorrectionMode = CORRECTION_BASIC;
public Suggest(Context context, int dictionaryResId) { public Suggest(Context context, int dictionaryResId) {
mMainDict = new BinaryDictionary(context, dictionaryResId, DIC_MAIN); mMainDict = BinaryDictionary.initDictionary(context, dictionaryResId, DIC_MAIN);
initPool(); initPool();
} }
@ -127,7 +129,7 @@ public class Suggest implements Dictionary.WordCallback {
} }
public boolean hasMainDictionary() { public boolean hasMainDictionary() {
return mMainDict.getSize() > LARGE_DICTIONARY_THRESHOLD; return mMainDict != null && mMainDict.getSize() > LARGE_DICTIONARY_THRESHOLD;
} }
public int getApproxMaxWordLength() { public int getApproxMaxWordLength() {
@ -198,7 +200,7 @@ public class Suggest implements Dictionary.WordCallback {
public SuggestedWords.Builder getSuggestedWordBuilder(View view, WordComposer wordComposer, public SuggestedWords.Builder getSuggestedWordBuilder(View view, WordComposer wordComposer,
CharSequence prevWordForBigram) { CharSequence prevWordForBigram) {
LatinImeLogger.onStartSuggestion(prevWordForBigram); LatinImeLogger.onStartSuggestion(prevWordForBigram);
mHaveCorrection = false; mHaveAutoCorrection = false;
mIsFirstCharCapitalized = wordComposer.isFirstCharCapitalized(); mIsFirstCharCapitalized = wordComposer.isFirstCharCapitalized();
mIsAllUpperCase = wordComposer.isAllUpperCase(); mIsAllUpperCase = wordComposer.isAllUpperCase();
collectGarbage(mSuggestions, mPrefMaxSuggestions); collectGarbage(mSuggestions, mPrefMaxSuggestions);
@ -273,10 +275,13 @@ public class Suggest implements Dictionary.WordCallback {
if (mSuggestions.size() > 0 && isValidWord(typedWord) if (mSuggestions.size() > 0 && isValidWord(typedWord)
&& (mCorrectionMode == CORRECTION_FULL && (mCorrectionMode == CORRECTION_FULL
|| mCorrectionMode == CORRECTION_FULL_BIGRAM)) { || mCorrectionMode == CORRECTION_FULL_BIGRAM)) {
mHaveCorrection = true; if (DBG) {
Log.d(TAG, "Auto corrected by CORRECTION_FULL.");
}
mHaveAutoCorrection = true;
} }
} }
mMainDict.getWords(wordComposer, this, mNextLettersFrequencies); if (mMainDict != null) mMainDict.getWords(wordComposer, this, mNextLettersFrequencies);
if ((mCorrectionMode == CORRECTION_FULL || mCorrectionMode == CORRECTION_FULL_BIGRAM) if ((mCorrectionMode == CORRECTION_FULL || mCorrectionMode == CORRECTION_FULL_BIGRAM)
&& mSuggestions.size() > 0 && mPriorities.length > 0) { && mSuggestions.size() > 0 && mPriorities.length > 0) {
// TODO: when the normalized score of the first suggestion is nearly equals to // TODO: when the normalized score of the first suggestion is nearly equals to
@ -289,7 +294,10 @@ public class Suggest implements Dictionary.WordCallback {
+ "(" + mAutoCorrectionThreshold + ")"); + "(" + mAutoCorrectionThreshold + ")");
} }
if (normalizedScore >= mAutoCorrectionThreshold) { if (normalizedScore >= mAutoCorrectionThreshold) {
mHaveCorrection = true; if (DBG) {
Log.d(TAG, "Auto corrected by S-threthhold.");
}
mHaveAutoCorrection = true;
} }
} }
} }
@ -331,7 +339,10 @@ public class Suggest implements Dictionary.WordCallback {
canAdd &= !TextUtils.equals(autoText, mSuggestions.get(i + 1)); canAdd &= !TextUtils.equals(autoText, mSuggestions.get(i + 1));
} }
if (canAdd) { if (canAdd) {
mHaveCorrection = true; if (DBG) {
Log.d(TAG, "Auto corrected by AUTOTEXT.");
}
mHaveAutoCorrection = true;
mSuggestions.add(i + 1, autoText); mSuggestions.add(i + 1, autoText);
i++; i++;
} }
@ -374,7 +385,7 @@ public class Suggest implements Dictionary.WordCallback {
} }
public boolean hasMinimalCorrection() { public boolean hasMinimalCorrection() {
return mHaveCorrection; return mHaveAutoCorrection;
} }
private boolean compareCaseInsensitive(final String mLowerOriginalWord, private boolean compareCaseInsensitive(final String mLowerOriginalWord,
@ -496,7 +507,7 @@ public class Suggest implements Dictionary.WordCallback {
} }
public boolean isValidWord(final CharSequence word) { public boolean isValidWord(final CharSequence word) {
if (word == null || word.length() == 0) { if (word == null || word.length() == 0 || mMainDict == null) {
return false; return false;
} }
return mMainDict.isValidWord(word) return mMainDict.isValidWord(word)

View File

@ -124,7 +124,7 @@ public class SuggestedWords {
addWord(previousSuggestions.getWord(pos)); addWord(previousSuggestions.getWord(pos));
mIsCompletions = false; mIsCompletions = false;
mTypedWordValid = false; mTypedWordValid = false;
mHasMinimalSuggestion = (previousSize > 1); mHasMinimalSuggestion = false;
return this; return this;
} }

View File

@ -36,6 +36,8 @@ import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
public class Utils { public class Utils {
private static final String TAG = Utils.class.getSimpleName();
private static boolean DBG = LatinImeLogger.sDBG;
/** /**
* Cancel an {@link AsyncTask}. * Cancel an {@link AsyncTask}.
@ -96,6 +98,29 @@ public class Utils {
// || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1; // || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1;
} }
public static boolean shouldBlockedBySafetyNetForAutoCorrection(SuggestedWords suggestions) {
// Safety net for auto correction.
// Actually if we hit this safety net, it's actually a bug.
if (suggestions.size() <= 1 || suggestions.mTypedWordValid) return false;
CharSequence typedWord = suggestions.getWord(0);
CharSequence candidateWord = suggestions.getWord(1);
final int typedWordLength = typedWord.length();
final int maxEditDistanceOfNativeDictionary = typedWordLength < 5 ? 2 : typedWordLength / 2;
final int distance = Utils.editDistance(typedWord, candidateWord);
if (DBG) {
Log.d(TAG, "Autocorrected edit distance = " + distance
+ ", " + maxEditDistanceOfNativeDictionary);
}
if (distance > maxEditDistanceOfNativeDictionary) {
Log.w(TAG, "(Error) The edit distance of this correction exceeds limit. "
+ "Turning off auto-correction.");
return true;
} else {
return false;
}
}
/* package */ static class RingCharBuffer { /* package */ static class RingCharBuffer {
private static RingCharBuffer sRingCharBuffer = new RingCharBuffer(); private static RingCharBuffer sRingCharBuffer = new RingCharBuffer();
private static final char PLACEHOLDER_DELIMITER_CHAR = '\uFFFC'; private static final char PLACEHOLDER_DELIMITER_CHAR = '\uFFFC';

View File

@ -16,9 +16,6 @@
package com.android.inputmethod.voice; package com.android.inputmethod.voice;
import com.android.inputmethod.latin.R;
import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Bitmap; import android.graphics.Bitmap;
@ -29,20 +26,21 @@ import android.graphics.Path;
import android.graphics.PathEffect; import android.graphics.PathEffect;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Handler; import android.os.Handler;
import android.util.TypedValue; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup.MarginLayoutParams; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import com.android.inputmethod.latin.R;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.ShortBuffer; import java.nio.ShortBuffer;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
@ -58,81 +56,55 @@ public class RecognitionView {
private View mView; private View mView;
private Context mContext; private Context mContext;
private ImageView mImage;
private TextView mText; private TextView mText;
private View mButton; private ImageView mImage;
private TextView mButtonText;
private View mProgress; private View mProgress;
private SoundIndicator mSoundIndicator;
private Button mButton;
private Drawable mInitializing; private Drawable mInitializing;
private Drawable mError; private Drawable mError;
private List<Drawable> mSpeakNow;
private float mVolume = 0.0f; private static final int INIT = 0;
private int mLevel = 0; private static final int LISTENING = 1;
private static final int WORKING = 2;
private static final int READY = 3;
private int mState = INIT;
private enum State {LISTENING, WORKING, READY} private final View mPopupLayout;
private State mState = State.READY;
private float mMinMicrophoneLevel; private final Drawable mListeningBorder;
private float mMaxMicrophoneLevel; private final Drawable mWorkingBorder;
private final Drawable mErrorBorder;
/** Updates the microphone icon to show user their volume.*/
private Runnable mUpdateVolumeRunnable = new Runnable() {
@Override
public void run() {
if (mState != State.LISTENING) {
return;
}
final float min = mMinMicrophoneLevel;
final float max = mMaxMicrophoneLevel;
final int maxLevel = mSpeakNow.size() - 1;
int index = (int) ((mVolume - min) / (max - min) * maxLevel);
final int level = Math.min(Math.max(0, index), maxLevel);
if (level != mLevel) {
mImage.setImageDrawable(mSpeakNow.get(level));
mLevel = level;
}
mUiHandler.postDelayed(mUpdateVolumeRunnable, 50);
}
};
public RecognitionView(Context context, OnClickListener clickListener) { public RecognitionView(Context context, OnClickListener clickListener) {
mUiHandler = new Handler(); mUiHandler = new Handler();
LayoutInflater inflater = (LayoutInflater) context.getSystemService( LayoutInflater inflater = (LayoutInflater) context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE); Context.LAYOUT_INFLATER_SERVICE);
mView = inflater.inflate(R.layout.recognition_status, null); mView = inflater.inflate(R.layout.recognition_status, null);
ContentResolver cr = context.getContentResolver();
mMinMicrophoneLevel = SettingsUtil.getSettingsFloat( mPopupLayout= mView.findViewById(R.id.popup_layout);
cr, SettingsUtil.LATIN_IME_MIN_MICROPHONE_LEVEL, 15.f);
mMaxMicrophoneLevel = SettingsUtil.getSettingsFloat(
cr, SettingsUtil.LATIN_IME_MAX_MICROPHONE_LEVEL, 30.f);
// Pre-load volume level images // Pre-load volume level images
Resources r = context.getResources(); Resources r = context.getResources();
mSpeakNow = new ArrayList<Drawable>(); mListeningBorder = r.getDrawable(R.drawable.vs_dialog_red);
mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level0)); mWorkingBorder = r.getDrawable(R.drawable.vs_dialog_blue);
mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level1)); mErrorBorder = r.getDrawable(R.drawable.vs_dialog_yellow);
mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level2));
mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level3));
mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level4));
mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level5));
mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level6));
mInitializing = r.getDrawable(R.drawable.mic_slash); mInitializing = r.getDrawable(R.drawable.mic_slash);
mError = r.getDrawable(R.drawable.caution); mError = r.getDrawable(R.drawable.caution);
mImage = (ImageView) mView.findViewById(R.id.image); mImage = (ImageView) mView.findViewById(R.id.image);
mButton = mView.findViewById(R.id.button); mProgress = mView.findViewById(R.id.progress);
mSoundIndicator = (SoundIndicator) mView.findViewById(R.id.sound_indicator);
mButton = (Button) mView.findViewById(R.id.button);
mButton.setOnClickListener(clickListener); mButton.setOnClickListener(clickListener);
mText = (TextView) mView.findViewById(R.id.text); mText = (TextView) mView.findViewById(R.id.text);
mButtonText = (TextView) mView.findViewById(R.id.button_text);
mProgress = mView.findViewById(R.id.progress);
mContext = context; mContext = context;
} }
@ -146,9 +118,9 @@ public class RecognitionView {
@Override @Override
public void run() { public void run() {
// Restart the spinner // Restart the spinner
if (mState == State.WORKING) { if (mState == WORKING) {
((ProgressBar)mProgress).setIndeterminate(false); ((ProgressBar) mProgress).setIndeterminate(false);
((ProgressBar)mProgress).setIndeterminate(true); ((ProgressBar) mProgress).setIndeterminate(true);
} }
} }
}); });
@ -158,48 +130,48 @@ public class RecognitionView {
mUiHandler.post(new Runnable() { mUiHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
prepareDialog(false, mContext.getText(R.string.voice_initializing), mInitializing, mState = INIT;
mContext.getText(R.string.cancel)); prepareDialog(mContext.getText(R.string.voice_initializing), mInitializing,
mContext.getText(R.string.cancel));
} }
}); });
} }
public void showListening() { public void showListening() {
Log.d(TAG, "#showListening");
mUiHandler.post(new Runnable() { mUiHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
mState = State.LISTENING; mState = LISTENING;
prepareDialog(false, mContext.getText(R.string.voice_listening), mSpeakNow.get(0), prepareDialog(mContext.getText(R.string.voice_listening), null,
mContext.getText(R.string.cancel)); mContext.getText(R.string.cancel));
} }
}); });
mUiHandler.postDelayed(mUpdateVolumeRunnable, 50);
} }
public void updateVoiceMeter(final float rmsdB) { public void updateVoiceMeter(float rmsdB) {
mVolume = rmsdB; mSoundIndicator.setRmsdB(rmsdB);
} }
public void showError(final String message) { public void showError(final String message) {
mUiHandler.post(new Runnable() { mUiHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
mState = State.READY; mState = READY;
prepareDialog(false, message, mError, mContext.getText(R.string.ok)); prepareDialog(message, mError, mContext.getText(R.string.ok));
} }
}); });
} }
public void showWorking( public void showWorking(
final ByteArrayOutputStream waveBuffer, final ByteArrayOutputStream waveBuffer,
final int speechStartPosition, final int speechStartPosition,
final int speechEndPosition) { final int speechEndPosition) {
mUiHandler.post(new Runnable() { mUiHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
mState = State.WORKING; mState = WORKING;
prepareDialog(true, mContext.getText(R.string.voice_working), null, mContext prepareDialog(mContext.getText(R.string.voice_working), null, mContext
.getText(R.string.cancel)); .getText(R.string.cancel));
final ShortBuffer buf = ByteBuffer.wrap(waveBuffer.toByteArray()).order( final ShortBuffer buf = ByteBuffer.wrap(waveBuffer.toByteArray()).order(
ByteOrder.nativeOrder()).asShortBuffer(); ByteOrder.nativeOrder()).asShortBuffer();
@ -207,21 +179,71 @@ public class RecognitionView {
waveBuffer.reset(); waveBuffer.reset();
showWave(buf, speechStartPosition / 2, speechEndPosition / 2); showWave(buf, speechStartPosition / 2, speechEndPosition / 2);
} }
}); });
} }
private void prepareDialog(boolean spinVisible, CharSequence text, Drawable image, private void prepareDialog(CharSequence text, Drawable image,
CharSequence btnTxt) { CharSequence btnTxt) {
if (spinVisible) { switch (mState) {
mProgress.setVisibility(View.VISIBLE); case INIT:
mImage.setVisibility(View.GONE); mText.setVisibility(View.GONE);
} else {
mProgress.setVisibility(View.GONE); mProgress.setVisibility(View.GONE);
mImage.setImageDrawable(image);
mImage.setVisibility(View.VISIBLE); mImage.setVisibility(View.VISIBLE);
mImage.setImageResource(R.drawable.mic_slash);
mSoundIndicator.setVisibility(View.GONE);
mSoundIndicator.stop();
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();
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();
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();
mPopupLayout.setBackgroundDrawable(mErrorBorder);
break;
default:
Log.w(TAG, "Unknown state " + mState);
} }
mText.setText(text); mPopupLayout.requestLayout();
mButtonText.setText(btnTxt); mButton.setText(btnTxt);
} }
/** /**
@ -248,7 +270,7 @@ public class RecognitionView {
*/ */
private void showWave(ShortBuffer waveBuffer, int startPosition, int endPosition) { private void showWave(ShortBuffer waveBuffer, int startPosition, int endPosition) {
final int w = ((View) mImage.getParent()).getWidth(); final int w = ((View) mImage.getParent()).getWidth();
final int h = mImage.getHeight(); final int h = ((View) mImage.getParent()).getHeight();
if (w <= 0 || h <= 0) { if (w <= 0 || h <= 0) {
// view is not visible this time. Skip drawing. // view is not visible this time. Skip drawing.
return; return;
@ -259,7 +281,7 @@ public class RecognitionView {
paint.setColor(0xFFFFFFFF); // 0xAARRGGBB paint.setColor(0xFFFFFFFF); // 0xAARRGGBB
paint.setAntiAlias(true); paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE); paint.setStyle(Paint.Style.STROKE);
paint.setAlpha(0x90); paint.setAlpha(80);
final PathEffect effect = new CornerPathEffect(3); final PathEffect effect = new CornerPathEffect(3);
paint.setPathEffect(effect); paint.setPathEffect(effect);
@ -281,7 +303,7 @@ public class RecognitionView {
final int count = (endIndex - startIndex) / numSamplePerWave; final int count = (endIndex - startIndex) / numSamplePerWave;
final float deltaX = 1.0f * w / count; final float deltaX = 1.0f * w / count;
int yMax = h / 2 - 8; int yMax = h / 2;
Path path = new Path(); Path path = new Path();
c.translate(0, yMax); c.translate(0, yMax);
float x = 0; float x = 0;
@ -295,37 +317,20 @@ public class RecognitionView {
path.lineTo(x, y); path.lineTo(x, y);
} }
if (deltaX > 4) { if (deltaX > 4) {
paint.setStrokeWidth(3); paint.setStrokeWidth(2);
} else { } else {
paint.setStrokeWidth(Math.max(1, (int) (deltaX -.05))); paint.setStrokeWidth(Math.max(0, (int) (deltaX -.05)));
} }
c.drawPath(path, paint); c.drawPath(path, paint);
mImage.setImageBitmap(b); mImage.setImageBitmap(b);
mImage.setVisibility(View.VISIBLE);
MarginLayoutParams mProgressParams = (MarginLayoutParams)mProgress.getLayoutParams();
mProgressParams.topMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
-h , mContext.getResources().getDisplayMetrics());
// Tweak the padding manually to fill out the whole view horizontally.
// TODO: Do this in the xml layout instead.
((View) mImage.getParent()).setPadding(4, ((View) mImage.getParent()).getPaddingTop(), 3,
((View) mImage.getParent()).getPaddingBottom());
mProgress.setLayoutParams(mProgressParams);
} }
public void finish() { public void finish() {
mUiHandler.post(new Runnable() { mUiHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
mState = State.READY; mSoundIndicator.stop();
exitWorking();
} }
}); });
}
private void exitWorking() {
mProgress.setVisibility(View.GONE);
mImage.setVisibility(View.VISIBLE);
} }
} }

View File

@ -0,0 +1,155 @@
/*
* Copyright (C) 2011 Google Inc.
*
* 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.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);
}
}

View File

@ -16,6 +16,7 @@
package com.android.inputmethod.voice; package com.android.inputmethod.voice;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.latin.EditingUtils; import com.android.inputmethod.latin.EditingUtils;
import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.LatinIME.UIHandler; import com.android.inputmethod.latin.LatinIME.UIHandler;
@ -29,6 +30,7 @@ import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.net.Uri; import android.net.Uri;
import android.os.IBinder; import android.os.IBinder;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
@ -77,6 +79,9 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
// dialog is already showing a voice search button. // dialog is already showing a voice search button.
private static final String IME_OPTION_NO_MICROPHONE = "nm"; private static final String IME_OPTION_NO_MICROPHONE = "nm";
@SuppressWarnings("unused")
private static final String TAG = "VoiceIMEConnector";
private boolean mAfterVoiceInput; private boolean mAfterVoiceInput;
private boolean mHasUsedVoiceInput; private boolean mHasUsedVoiceInput;
private boolean mHasUsedVoiceInputUnsupportedLocale; private boolean mHasUsedVoiceInputUnsupportedLocale;
@ -91,7 +96,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
private boolean mVoiceInputHighlighted; private boolean mVoiceInputHighlighted;
private InputMethodManager mImm; private InputMethodManager mImm;
private LatinIME mContext; private LatinIME mService;
private AlertDialog mVoiceWarningDialog; private AlertDialog mVoiceWarningDialog;
private VoiceInput mVoiceInput; private VoiceInput mVoiceInput;
private final VoiceResults mVoiceResults = new VoiceResults(); private final VoiceResults mVoiceResults = new VoiceResults();
@ -111,21 +116,19 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
return sInstance; return sInstance;
} }
private void initInternal(LatinIME context, SharedPreferences prefs, UIHandler h) { private void initInternal(LatinIME service, SharedPreferences prefs, UIHandler h) {
mContext = context; mService = service;
mHandler = h; mHandler = h;
mImm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); mImm = (InputMethodManager) service.getSystemService(Context.INPUT_METHOD_SERVICE);
mSubtypeSwitcher = SubtypeSwitcher.getInstance(); mSubtypeSwitcher = SubtypeSwitcher.getInstance();
if (VOICE_INSTALLED) { if (VOICE_INSTALLED) {
mVoiceInput = new VoiceInput(context, this); mVoiceInput = new VoiceInput(service, this);
mHints = new Hints(context, prefs, new Hints.Display() { mHints = new Hints(service, prefs, new Hints.Display() {
@Override @Override
public void showHint(int viewResource) { public void showHint(int viewResource) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( View view = LayoutInflater.from(mService).inflate(viewResource, null);
Context.LAYOUT_INFLATER_SERVICE); mService.setCandidatesView(view);
View view = inflater.inflate(viewResource, null); mService.setCandidatesViewShown(true);
mContext.setCandidatesView(view);
mContext.setCandidatesViewShown(true);
mIsShowingHint = true; mIsShowingHint = true;
} }
}); });
@ -161,23 +164,22 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
mVoiceInput.flushAllTextModificationCounters(); mVoiceInput.flushAllTextModificationCounters();
// send this intent AFTER logging any prior aggregated edits. // send this intent AFTER logging any prior aggregated edits.
mVoiceInput.logTextModifiedByChooseSuggestion(suggestion.toString(), index, mVoiceInput.logTextModifiedByChooseSuggestion(suggestion.toString(), index,
wordSeparators, mContext.getCurrentInputConnection()); wordSeparators, mService.getCurrentInputConnection());
} }
} }
private void showVoiceWarningDialog(final boolean swipe, IBinder token, private void showVoiceWarningDialog(final boolean swipe, IBinder token) {
final boolean configurationChanging) {
if (mVoiceWarningDialog != null && mVoiceWarningDialog.isShowing()) { if (mVoiceWarningDialog != null && mVoiceWarningDialog.isShowing()) {
return; return;
} }
AlertDialog.Builder builder = new AlertDialog.Builder(mContext); AlertDialog.Builder builder = new AlertDialog.Builder(mService);
builder.setCancelable(true); builder.setCancelable(true);
builder.setIcon(R.drawable.ic_mic_dialog); builder.setIcon(R.drawable.ic_mic_dialog);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int whichButton) { public void onClick(DialogInterface dialog, int whichButton) {
mVoiceInput.logKeyboardWarningDialogOk(); mVoiceInput.logKeyboardWarningDialogOk();
reallyStartListening(swipe, configurationChanging); reallyStartListening(swipe);
} }
}); });
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@ -199,13 +201,13 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
final CharSequence message; final CharSequence message;
if (mLocaleSupportedForVoiceInput) { if (mLocaleSupportedForVoiceInput) {
message = TextUtils.concat( message = TextUtils.concat(
mContext.getText(R.string.voice_warning_may_not_understand), "\n\n", mService.getText(R.string.voice_warning_may_not_understand), "\n\n",
mContext.getText(R.string.voice_warning_how_to_turn_off)); mService.getText(R.string.voice_warning_how_to_turn_off));
} else { } else {
message = TextUtils.concat( message = TextUtils.concat(
mContext.getText(R.string.voice_warning_locale_not_supported), "\n\n", mService.getText(R.string.voice_warning_locale_not_supported), "\n\n",
mContext.getText(R.string.voice_warning_may_not_understand), "\n\n", mService.getText(R.string.voice_warning_may_not_understand), "\n\n",
mContext.getText(R.string.voice_warning_how_to_turn_off)); mService.getText(R.string.voice_warning_how_to_turn_off));
} }
builder.setMessage(message); builder.setMessage(message);
@ -296,7 +298,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
} }
public void showPunctuationHintIfNecessary() { public void showPunctuationHintIfNecessary() {
InputConnection ic = mContext.getCurrentInputConnection(); InputConnection ic = mService.getCurrentInputConnection();
if (!mImmediatelyAfterVoiceInput && mAfterVoiceInput && ic != null) { if (!mImmediatelyAfterVoiceInput && mAfterVoiceInput && ic != null) {
if (mHints.showPunctuationHintIfNecessary(ic)) { if (mHints.showPunctuationHintIfNecessary(ic)) {
mVoiceInput.logPunctuationHintDisplayed(); mVoiceInput.logPunctuationHintDisplayed();
@ -364,17 +366,17 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
} }
private void revertVoiceInput() { private void revertVoiceInput() {
InputConnection ic = mContext.getCurrentInputConnection(); InputConnection ic = mService.getCurrentInputConnection();
if (ic != null) ic.commitText("", 1); if (ic != null) ic.commitText("", 1);
mContext.updateSuggestions(); mService.updateSuggestions();
mVoiceInputHighlighted = false; mVoiceInputHighlighted = false;
} }
public void commitVoiceInput() { public void commitVoiceInput() {
if (VOICE_INSTALLED && mVoiceInputHighlighted) { if (VOICE_INSTALLED && mVoiceInputHighlighted) {
InputConnection ic = mContext.getCurrentInputConnection(); InputConnection ic = mService.getCurrentInputConnection();
if (ic != null) ic.finishComposingText(); if (ic != null) ic.finishComposingText();
mContext.updateSuggestions(); mService.updateSuggestions();
mVoiceInputHighlighted = false; mVoiceInputHighlighted = false;
} }
} }
@ -394,7 +396,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
if (mShowingVoiceSuggestions) { if (mShowingVoiceSuggestions) {
// Retain the replaced word in the alternatives array. // Retain the replaced word in the alternatives array.
String wordToBeReplaced = EditingUtils.getWordAtCursor( String wordToBeReplaced = EditingUtils.getWordAtCursor(
mContext.getCurrentInputConnection(), wordSeparators); mService.getCurrentInputConnection(), wordSeparators);
if (!mWordToSuggestions.containsKey(wordToBeReplaced)) { if (!mWordToSuggestions.containsKey(wordToBeReplaced)) {
wordToBeReplaced = wordToBeReplaced.toLowerCase(); wordToBeReplaced = wordToBeReplaced.toLowerCase();
} }
@ -438,8 +440,8 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
builder.addWords(suggestions); builder.addWords(suggestions);
} }
builder.setTypedWordValid(true).setHasMinimalSuggestion(true); builder.setTypedWordValid(true).setHasMinimalSuggestion(true);
mContext.setSuggestions(builder.build()); mService.setSuggestions(builder.build());
mContext.setCandidatesViewShown(true); mService.setCandidatesViewShown(true);
return true; return true;
} }
return false; return false;
@ -486,15 +488,15 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
mAfterVoiceInput = true; mAfterVoiceInput = true;
mImmediatelyAfterVoiceInput = true; mImmediatelyAfterVoiceInput = true;
InputConnection ic = mContext.getCurrentInputConnection(); InputConnection ic = mService.getCurrentInputConnection();
if (!mContext.isFullscreenMode()) { if (!mService.isFullscreenMode()) {
// Start listening for updates to the text from typing, etc. // Start listening for updates to the text from typing, etc.
if (ic != null) { if (ic != null) {
ExtractedTextRequest req = new ExtractedTextRequest(); ExtractedTextRequest req = new ExtractedTextRequest();
ic.getExtractedText(req, InputConnection.GET_EXTRACTED_TEXT_MONITOR); ic.getExtractedText(req, InputConnection.GET_EXTRACTED_TEXT_MONITOR);
} }
} }
mContext.vibrate(); mService.vibrate();
final List<CharSequence> nBest = new ArrayList<CharSequence>(); final List<CharSequence> nBest = new ArrayList<CharSequence>();
for (String c : mVoiceResults.candidates) { for (String c : mVoiceResults.candidates) {
@ -511,7 +513,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
mHints.registerVoiceResult(bestResult); mHints.registerVoiceResult(bestResult);
if (ic != null) ic.beginBatchEdit(); // To avoid extra updates on committing older text if (ic != null) ic.beginBatchEdit(); // To avoid extra updates on committing older text
mContext.commitTyped(ic); mService.commitTyped(ic);
EditingUtils.appendText(ic, bestResult); EditingUtils.appendText(ic, bestResult);
if (ic != null) ic.endBatchEdit(); if (ic != null) ic.endBatchEdit();
@ -520,22 +522,38 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
onCancelVoice(); onCancelVoice();
} }
public void switchToRecognitionStatusView(final boolean configurationChanging) { public void switchToRecognitionStatusView(final Configuration configuration) {
final boolean configChanged = configurationChanging;
mHandler.post(new Runnable() { mHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
mContext.setCandidatesViewShown(false); mService.setCandidatesViewShown(false);
mRecognizing = true; mRecognizing = true;
mVoiceInput.newView();
View v = mVoiceInput.getView(); View v = mVoiceInput.getView();
ViewParent p = v.getParent(); ViewParent p = v.getParent();
if (p != null && p instanceof ViewGroup) { if (p != null && p instanceof ViewGroup) {
((ViewGroup)p).removeView(v); ((ViewGroup) p).removeView(v);
} }
mContext.setInputView(v);
mContext.updateInputViewShown(); View keyboardView = KeyboardSwitcher.getInstance().getInputView();
if (configChanged) {
mVoiceInput.onConfigurationChanged(); // 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) {
int h = keyboardView.getHeight();
if (h > 0) {
View popupLayout = v.findViewById(R.id.popup_layout);
popupLayout.getLayoutParams().height = h;
}
}
mService.setInputView(v);
mService.updateInputViewShown();
if (configuration != null) {
mVoiceInput.onConfigurationChanged(configuration);
} }
}}); }});
} }
@ -547,7 +565,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
*/ */
} }
private void reallyStartListening(boolean swipe, final boolean configurationChanging) { private void reallyStartListening(boolean swipe) {
if (!VOICE_INSTALLED) { if (!VOICE_INSTALLED) {
return; return;
} }
@ -555,7 +573,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
// The user has started a voice input, so remember that in the // 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). // future (so we don't show the warning dialog after the first run).
SharedPreferences.Editor editor = SharedPreferences.Editor editor =
PreferenceManager.getDefaultSharedPreferences(mContext).edit(); PreferenceManager.getDefaultSharedPreferences(mService).edit();
editor.putBoolean(PREF_HAS_USED_VOICE_INPUT, true); editor.putBoolean(PREF_HAS_USED_VOICE_INPUT, true);
SharedPreferencesCompat.apply(editor); SharedPreferencesCompat.apply(editor);
mHasUsedVoiceInput = true; mHasUsedVoiceInput = true;
@ -565,34 +583,32 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
// The user has started a voice input from an unsupported locale, so remember that // 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). // in the future (so we don't show the warning dialog the next time they do this).
SharedPreferences.Editor editor = SharedPreferences.Editor editor =
PreferenceManager.getDefaultSharedPreferences(mContext).edit(); PreferenceManager.getDefaultSharedPreferences(mService).edit();
editor.putBoolean(PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE, true); editor.putBoolean(PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE, true);
SharedPreferencesCompat.apply(editor); SharedPreferencesCompat.apply(editor);
mHasUsedVoiceInputUnsupportedLocale = true; mHasUsedVoiceInputUnsupportedLocale = true;
} }
// Clear N-best suggestions // Clear N-best suggestions
mContext.clearSuggestions(); mService.clearSuggestions();
FieldContext context = makeFieldContext(); FieldContext context = makeFieldContext();
mVoiceInput.startListening(context, swipe); mVoiceInput.startListening(context, swipe);
switchToRecognitionStatusView(configurationChanging); switchToRecognitionStatusView(null);
} }
public void startListening(final boolean swipe, IBinder token, public void startListening(final boolean swipe, IBinder token) {
final boolean configurationChanging) {
// TODO: remove swipe which is no longer used. // TODO: remove swipe which is no longer used.
if (VOICE_INSTALLED) { if (VOICE_INSTALLED) {
if (needsToShowWarningDialog()) { if (needsToShowWarningDialog()) {
// Calls reallyStartListening if user clicks OK, does nothing if user clicks Cancel. // Calls reallyStartListening if user clicks OK, does nothing if user clicks Cancel.
showVoiceWarningDialog(swipe, token, configurationChanging); showVoiceWarningDialog(swipe, token);
} else { } else {
reallyStartListening(swipe, configurationChanging); reallyStartListening(swipe);
} }
} }
} }
private boolean fieldCanDoVoice(FieldContext fieldContext) { private boolean fieldCanDoVoice(FieldContext fieldContext) {
return !mPasswordText return !mPasswordText
&& mVoiceInput != null && mVoiceInput != null
@ -603,7 +619,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
return ENABLE_VOICE_BUTTON && fieldCanDoVoice(fieldContext) return ENABLE_VOICE_BUTTON && fieldCanDoVoice(fieldContext)
&& !(attribute != null && !(attribute != null
&& IME_OPTION_NO_MICROPHONE.equals(attribute.privateImeOptions)) && IME_OPTION_NO_MICROPHONE.equals(attribute.privateImeOptions))
&& SpeechRecognizer.isRecognitionAvailable(mContext); && SpeechRecognizer.isRecognitionAvailable(mService);
} }
public void loadSettings(EditorInfo attribute, SharedPreferences sp) { public void loadSettings(EditorInfo attribute, SharedPreferences sp) {
@ -616,10 +632,10 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
if (VOICE_INSTALLED) { if (VOICE_INSTALLED) {
final String voiceMode = sp.getString(PREF_VOICE_MODE, final String voiceMode = sp.getString(PREF_VOICE_MODE,
mContext.getString(R.string.voice_mode_main)); mService.getString(R.string.voice_mode_main));
mVoiceButtonEnabled = !voiceMode.equals(mContext.getString(R.string.voice_mode_off)) mVoiceButtonEnabled = !voiceMode.equals(mService.getString(R.string.voice_mode_off))
&& shouldShowVoiceButton(makeFieldContext(), attribute); && shouldShowVoiceButton(makeFieldContext(), attribute);
mVoiceButtonOnPrimary = voiceMode.equals(mContext.getString(R.string.voice_mode_main)); mVoiceButtonOnPrimary = voiceMode.equals(mService.getString(R.string.voice_mode_main));
} }
} }
@ -632,9 +648,14 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
public void onStartInputView(IBinder token) { public void onStartInputView(IBinder token) {
// If IME is in voice mode, but still needs to show the voice warning dialog, // If IME is in voice mode, but still needs to show the voice warning dialog,
// keep showing the warning. // keep showing the warning.
if (mSubtypeSwitcher.isVoiceMode() && needsToShowWarningDialog() && token != null) { if (mSubtypeSwitcher.isVoiceMode() && token != null) {
showVoiceWarningDialog(false, token, false); // Close keyboard view if it is been shown.
if (KeyboardSwitcher.getInstance().isInputViewShown())
KeyboardSwitcher.getInstance().getInputView().purgeKeyboardAndClosing();
startListening(false, token);
} }
// If we have no token, onAttachedToWindow will take care of showing dialog and start
// listening.
} }
public void onAttachedToWindow() { public void onAttachedToWindow() {
@ -643,9 +664,9 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
mSubtypeSwitcher.setVoiceInput(mVoiceInput); mSubtypeSwitcher.setVoiceInput(mVoiceInput);
} }
public void onConfigurationChanged(boolean configurationChanging) { public void onConfigurationChanged(Configuration configuration) {
if (mRecognizing) { if (mRecognizing) {
switchToRecognitionStatusView(configurationChanging); switchToRecognitionStatusView(configuration);
} }
} }
@ -664,7 +685,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
// onCurrentInputMethodSubtypeChanged() will be called first. LatinIME will know // onCurrentInputMethodSubtypeChanged() will be called first. LatinIME will know
// that it's in keyboard mode and SubtypeSwitcher will call onCancelVoice(). // that it's in keyboard mode and SubtypeSwitcher will call onCancelVoice().
mRecognizing = false; mRecognizing = false;
mContext.switchToKeyboardView(); mService.switchToKeyboardView();
} }
} }
} }
@ -682,8 +703,8 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
public FieldContext makeFieldContext() { public FieldContext makeFieldContext() {
SubtypeSwitcher switcher = SubtypeSwitcher.getInstance(); SubtypeSwitcher switcher = SubtypeSwitcher.getInstance();
return new FieldContext(mContext.getCurrentInputConnection(), return new FieldContext(mService.getCurrentInputConnection(),
mContext.getCurrentInputEditorInfo(), switcher.getInputLocaleStr(), mService.getCurrentInputEditorInfo(), switcher.getInputLocaleStr(),
switcher.getEnabledLanguages()); switcher.getEnabledLanguages());
} }

View File

@ -22,6 +22,7 @@ import com.android.inputmethod.latin.R;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.res.Configuration;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
@ -129,12 +130,17 @@ public class VoiceInput implements OnClickListener {
private final static int MSG_CLOSE_ERROR_DIALOG = 1; private final static int MSG_CLOSE_ERROR_DIALOG = 1;
private final static int MSG_RESET = 2;
private final Handler mHandler = new Handler() { private final Handler mHandler = new Handler() {
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
if (msg.what == MSG_CLOSE_ERROR_DIALOG) { if (msg.what == MSG_RESET || msg.what == MSG_CLOSE_ERROR_DIALOG) {
mState = DEFAULT; mState = DEFAULT;
mRecognitionView.finish(); mRecognitionView.finish();
}
if (msg.what == MSG_CLOSE_ERROR_DIALOG) {
mUiListener.onCancelVoice(); mUiListener.onCancelVoice();
} }
} }
@ -277,8 +283,9 @@ public class VoiceInput implements OnClickListener {
* The configuration of the IME changed and may have caused the views to be layed out * The configuration of the IME changed and may have caused the views to be layed out
* again. Restore the state of the recognition view. * again. Restore the state of the recognition view.
*/ */
public void onConfigurationChanged() { public void onConfigurationChanged(Configuration configuration) {
mRecognitionView.restoreState(); mRecognitionView.restoreState();
mRecognitionView.getView().dispatchConfigurationChanged(configuration);
} }
/** /**
@ -509,7 +516,7 @@ public class VoiceInput implements OnClickListener {
mState = DEFAULT; mState = DEFAULT;
// Remove all pending tasks (e.g., timers to cancel voice input) // Remove all pending tasks (e.g., timers to cancel voice input)
mHandler.removeMessages(MSG_CLOSE_ERROR_DIALOG); mHandler.removeMessages(MSG_RESET);
mSpeechRecognizer.cancel(); mSpeechRecognizer.cancel();
mUiListener.onCancelVoice(); mUiListener.onCancelVoice();

View File

@ -89,7 +89,7 @@ static jint latinime_BinaryDictionary_open(JNIEnv *env, jobject object,
return 0; return 0;
} }
dictBuf = malloc(sizeof(char) * dictSize); dictBuf = malloc(sizeof(char) * dictSize);
if (dictBuf == NULL) { if (!dictBuf) {
LOGE("DICT: Can't allocate memory region for dictionary. errno=%d", errno); LOGE("DICT: Can't allocate memory region for dictionary. errno=%d", errno);
return 0; return 0;
} }

View File

@ -0,0 +1,106 @@
/*
* 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.latin;
import android.content.Context;
import android.content.res.Resources;
import android.test.AndroidTestCase;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class SubtypeLocaleTests extends AndroidTestCase {
private static final String PACKAGE = LatinIME.class.getPackage().getName();
private Resources mRes;
private List<InputMethodSubtype> mKeyboardSubtypes;
public interface Predicator<T> {
public boolean evaluate(T object);
}
private static <T> List<T> filter(List<T> source, Predicator<? super T> predicator) {
final ArrayList<T> filtered = new ArrayList<T>();
for (final T element : source) {
if (predicator.evaluate(element))
filtered.add(element);
}
return filtered;
}
@Override
protected void setUp() throws Exception {
super.setUp();
final Context context = getContext();
mRes = context.getResources();
SubtypeLocale.init(context);
final InputMethodManager imm = (InputMethodManager) context.getSystemService(
Context.INPUT_METHOD_SERVICE);
for (final InputMethodInfo imi : imm.getInputMethodList()) {
if (imi.getPackageName().equals(PACKAGE)) {
mKeyboardSubtypes = filter(imi.getSubtypes(),
new Predicator<InputMethodSubtype>() {
@Override
public boolean evaluate(InputMethodSubtype ims) {
return ims.getMode().equals("keyboard");
}
});
break;
}
}
assertNotNull("Can not find input method " + PACKAGE, mKeyboardSubtypes);
assertTrue("Can not find keyboard subtype", mKeyboardSubtypes.size() > 0);
}
// Copied from {@link java.junit.Assert#format(String, Object, Object)}
private static String format(String message, Object expected, Object actual) {
return message + " expected:<" + expected + "> but was:<" + actual + ">";
}
private String getStringWithLocale(int resId, Locale locale) {
final Locale savedLocale = Locale.getDefault();
try {
Locale.setDefault(locale);
return mRes.getString(resId);
} finally {
Locale.setDefault(savedLocale);
}
}
public void testSubtypeLocale() {
for (final InputMethodSubtype subtype : mKeyboardSubtypes) {
final String localeCode = subtype.getLocale();
final Locale locale = new Locale(localeCode);
// The locale name which will be displayed on spacebar. For example 'English (US)' or
// 'Francais (Canada)'. (c=\u008d)
final String displayName = SubtypeLocale.getFullDisplayName(locale);
// The subtype name in its locale. For example 'English (US) Keyboard' or
// 'Clavier Francais (Canada)'. (c=\u008d)
final String subtypeName = getStringWithLocale(subtype.getNameResId(), locale);
assertTrue(
format("subtype display name of " + localeCode + ":", subtypeName, displayName),
subtypeName.contains(displayName));
}
}
}