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
** limitations under the License.
*/
-->
<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"
-->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
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_height="42dip"
android:paddingLeft="1dip"
android:paddingRight="1dip"
>
<TextView android:id="@+id/button_text"
android:text="@string/cancel"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="7dip"
android:textSize="19sp"
android:textColor="#ffffff"
android:layout_gravity="center_horizontal"
/>
android:background="@drawable/background_voice">
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/popup_layout"
android:orientation="vertical"
android:layout_height="0dip"
android:layout_width="500dip"
android:layout_centerInParent="true"
android:background="@drawable/vs_dialog_red">
<TextView
android:id="@+id/text"
android:text="@string/voice_error"
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>

View File

@ -22,12 +22,19 @@
<bool name="config_enable_show_settings_key_option">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_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_swipe_down_dismiss_keyboard_enabled">false</bool>
<bool name="config_sliding_key_input_enabled">false</bool>
<bool name="config_digit_popup_characters_enabled">false</bool>
<!-- Whether or not Popup on key press is enabled by default -->
<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}. -->
<string name="config_default_keyboard_theme_id" translatable="false">5</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">
<!-- 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>

View File

@ -25,12 +25,25 @@
<bool name="config_enable_show_settings_key_option">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_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_swipe_down_dismiss_keyboard_enabled">true</bool>
<bool name="config_sliding_key_input_enabled">true</bool>
<bool name="config_digit_popup_characters_enabled">true</bool>
<!-- Whether or not Popup on key press is enabled by default -->
<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_after_preview">10</integer>
<integer name="config_preview_fadein_anim_time">0</integer>

View File

@ -138,4 +138,14 @@
<item>4</item>
<item>5</item>
</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>

View File

@ -22,7 +22,7 @@
<string name="english_ime_name">Android keyboard</string>
<!-- Title for Latin keyboard settings activity / dialog -->
<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>
<!-- 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 -->
<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 -->
<string name="prediction_category">Word suggestion settings</string>
<string name="prediction_category">Text correction</string>
<!-- Option to enable auto capitalization of sentences -->
<string name="auto_cap">Auto-capitalization</string>
@ -46,7 +49,7 @@
<string name="quick_fixes_summary">Corrects commonly typed mistakes</string>
<!-- 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 -->
<string name="prefs_show_suggestions_summary">Display suggested words while typing</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>
<!-- 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>
<!-- 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>
<!-- 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>
<!-- Short message to tell the user the system is ready for them to speak. -->

View File

@ -57,7 +57,6 @@
<key-style
latin:styleName="nonSpecialBackgroundSpaceKeyStyle"
latin:code="@integer/key_space"
latin:keyIcon="@drawable/sym_keyboard_space_holo"
latin:iconPreview="@drawable/sym_keyboard_feedback_space" />
<key-style
latin:styleName="smileyKeyStyle"
@ -66,6 +65,12 @@
latin:keyHintIcon="@drawable/hint_popup_holo"
latin:popupCharacters="@string/alternates_for_smiley"
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
latin:styleName="micKeyStyle"
latin:code="@integer/key_voice"
@ -102,12 +107,10 @@
<key-style
latin:styleName="spaceKeyStyle"
latin:code="@integer/key_space"
latin:keyIcon="@drawable/sym_bkeyboard_space"
latin:iconPreview="@drawable/sym_keyboard_feedback_space" />
<key-style
latin:styleName="nonSpecialBackgroundSpaceKeyStyle"
latin:code="@integer/key_space"
latin:keyIcon="@drawable/sym_bkeyboard_space"
latin:iconPreview="@drawable/sym_keyboard_feedback_space" />
<key-style
latin:styleName="smileyKeyStyle"
@ -116,6 +119,12 @@
latin:keyHintIcon="@drawable/hint_popup_holo"
latin:popupCharacters="@string/alternates_for_smiley"
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
latin:styleName="micKeyStyle"
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
the touch event on the area, "space" is intentionally not marked as a left edge key. -->
<Spacer
latin:horizontalGap="16.406%p" />
latin:horizontalGap="8.362%p" />
<Key
latin:keyStyle="settingsKeyStyle"
latin:keyWidth="8.042%p" />
<Key
latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle"
latin:keyWidth="24.127%p" />

View File

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

View File

@ -128,10 +128,13 @@
<!-- 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. -->
<Spacer
latin:horizontalGap="20.427%p" />
latin:horizontalGap="12.340%p" />
<Key
latin:keyStyle="settingsKeyStyle"
latin:keyWidth="8.042%p" />
<Key
latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle"
latin:keyWidth="16.085%p" />
latin:keyWidth="16.084%p" />
<Spacer
latin:horizontalGap="8.479%p" />
<Key

View File

@ -140,7 +140,10 @@
<!-- 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. -->
<Spacer
latin:horizontalGap="16.406%p" />
latin:horizontalGap="8.362%p" />
<Key
latin:keyStyle="settingsKeyStyle"
latin:keyWidth="8.042%p" />
<Key
latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle"
latin:keyWidth="24.127%p" />

View File

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

View File

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

View File

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

View File

@ -4,9 +4,9 @@
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.
@ -18,62 +18,68 @@
android:title="@string/english_ime_settings"
android:key="english_ime_settings">
<CheckBoxPreference
android:key="vibrate_on"
android:title="@string/vibrate_on_keypress"
android:persistent="true"
/>
<PreferenceCategory
android:title="@string/general_category"
android:key="general_settings">
<CheckBoxPreference
android:key="sound_on"
android:title="@string/sound_on_keypress"
android:persistent="true"
/>
<CheckBoxPreference
android:key="auto_cap"
android:title="@string/auto_cap"
android:persistent="true"
android:defaultValue="true"
/>
<CheckBoxPreference
android:key="popup_on"
android:title="@string/popup_on_keypress"
android:persistent="true"
android:defaultValue="@bool/config_default_popup_preview"
/>
<CheckBoxPreference
android:key="vibrate_on"
android:title="@string/vibrate_on_keypress"
android:persistent="true"
/>
<CheckBoxPreference
android:key="recorrection_enabled"
android:title="@string/prefs_enable_recorrection"
android:summary="@string/prefs_enable_recorrection_summary"
android:persistent="true"
android:defaultValue="@bool/default_recorrection_enabled"
/>
<CheckBoxPreference
android:key="sound_on"
android:title="@string/sound_on_keypress"
android:persistent="true"
/>
<CheckBoxPreference
android:key="auto_cap"
android:title="@string/auto_cap"
android:persistent="true"
android:defaultValue="true"
/>
<CheckBoxPreference
android:key="popup_on"
android:title="@string/popup_on_keypress"
android:persistent="true"
android:defaultValue="@bool/config_default_popup_preview"
/>
<ListPreference
android:key="settings_key"
android:title="@string/prefs_settings_key"
android:persistent="true"
android:entryValues="@array/settings_key_modes_values"
android:entries="@array/settings_key_modes"
android:defaultValue="@string/settings_key_mode_auto"
/>
<CheckBoxPreference
android:key="recorrection_enabled"
android:title="@string/prefs_enable_recorrection"
android:summary="@string/prefs_enable_recorrection_summary"
android:persistent="true"
android:defaultValue="@bool/default_recorrection_enabled"
/>
<ListPreference
android:key="voice_mode"
android:title="@string/voice_input"
android:persistent="true"
android:entryValues="@array/voice_input_modes_values"
android:entries="@array/voice_input_modes"
android:defaultValue="@string/voice_mode_main"
/>
<ListPreference
android:key="settings_key"
android:title="@string/prefs_settings_key"
android:persistent="true"
android:entryValues="@array/settings_key_modes_values"
android:entries="@array/settings_key_modes"
android:defaultValue="@string/settings_key_mode_auto"
/>
<PreferenceScreen
android:key="subtype_settings"
android:title="@string/language_selection_title"
android:summary="@string/language_selection_summary" />
<ListPreference
android:key="voice_mode"
android:title="@string/voice_input"
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
android:title="@string/prediction_category"
@ -87,16 +93,6 @@
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
android:key="auto_correction_threshold"
android:title="@string/auto_correction"
@ -107,6 +103,16 @@
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
android:key="bigram_suggestion"
android:title="@string/bigram_suggestion"

View File

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

View File

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

View File

@ -157,7 +157,15 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
boolean voiceButtonOnPrimary) {
mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA;
try {
if (mInputView == null) return;
final Keyboard oldKeyboard = mInputView.getKeyboard();
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) {
Log.w(TAG, 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,
boolean voiceButtonOnPrimary, boolean isSymbols) {
if (mInputView == null) return;
mInputView.setPreviewEnabled(mInputMethodService.getPopupOn());
mMode = mode;
mImeOptions = imeOptions;
@ -176,13 +183,16 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
mIsSymbols = isSymbols;
// Update the settings key state because number of enabled IMEs could have been changed
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();
KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols);
LatinKeyboard keyboard = getKeyboard(id);
mCurrentId = id;
mInputView.setKeyboard(keyboard);
mInputView.setPreviewEnabled(mInputMethodService.getPopupOn());
mInputView.setKeyboard(getKeyboard(id));
}
private LatinKeyboard getKeyboard(KeyboardId id) {
@ -210,6 +220,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
keyboard.onAutoCorrectionStateChanged(mIsAutoCorrectionActive);
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;
}
@ -313,6 +327,13 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
return false;
}
private boolean isManualTemporaryUpperCaseFromAuto() {
LatinKeyboard latinKeyboard = getLatinKeyboard();
if (latinKeyboard != null)
return latinKeyboard.isManualTemporaryUpperCaseFromAuto();
return false;
}
private void setManualTemporaryUpperCase(boolean shifted) {
LatinKeyboard latinKeyboard = getLatinKeyboard();
if (latinKeyboard != null) {
@ -468,6 +489,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
} else if (isShiftedOrShiftLocked() && shiftKeyState.isPressingOnShifted()) {
// Shift has been pressed without chording while shifted state.
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();

View File

@ -298,8 +298,6 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView);
LayoutInflater inflate =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int previewLayout = 0;
int keyTextSize = 0;
@ -365,7 +363,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
mPreviewPopup = new PopupWindow(context);
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);
mPreviewPopup.setContentView(mPreviewText);
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
// 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.
@SuppressWarnings("unused")
final boolean hidePreviewOrShowSpaceKeyPreview = (tracker == null)
|| (SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER
|| (SubtypeSwitcher.getInstance().useSpacebarLanguageSwitcher()
&& SubtypeSwitcher.getInstance().needsToDisplayLanguage()
&& (tracker.isSpaceKey(keyIndex) || tracker.isSpaceKey(oldKeyIndex)));
// 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) {
int popupKeyboardResId = mKeyboard.getPopupKeyboardResId();
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
View container = inflater.inflate(mPopupLayout, null);
View container = LayoutInflater.from(getContext()).inflate(mPopupLayout, null);
if (container == null)
throw new NullPointerException();
@ -1410,6 +1405,12 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
mBuffer = null;
mCanvas = null;
mMiniKeyboardCache.clear();
requestLayout();
}
public void purgeKeyboardAndClosing() {
mKeyboard = null;
closing();
}
@Override

View File

@ -24,6 +24,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.PorterDuff;
@ -47,7 +48,9 @@ public class LatinKeyboard extends Keyboard {
private final Drawable mSpaceAutoCorrectionIndicator;
private final Drawable mButtonArrowLeftIcon;
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 int mSpaceDragStartX;
private int mSpaceDragLastDiff;
@ -80,11 +83,12 @@ public class LatinKeyboard extends Keyboard {
super(context, id.getXmlId(), id);
final Resources res = context.getResources();
mContext = context;
mSpacebarTextColor = res.getColor(R.color.latinkeyboard_bar_language_text);
if (id.mColorScheme == KeyboardView.COLOR_SCHEME_BLACK) {
mSpaceBarTextShadowColor = res.getColor(
mSpacebarTextShadowColor = res.getColor(
R.color.latinkeyboard_bar_language_shadow_black);
} else { // default color scheme is KeyboardView.COLOR_SCHEME_WHITE
mSpaceBarTextShadowColor = res.getColor(
mSpacebarTextShadowColor = res.getColor(
R.color.latinkeyboard_bar_language_shadow_white);
}
mSpaceAutoCorrectionIndicator = res.getDrawable(R.drawable.sym_keyboard_space_led);
@ -96,25 +100,38 @@ public class LatinKeyboard extends Keyboard {
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.
*/
public Key onAutoCorrectionStateChanged(boolean isAutoCorrection) {
updateSpaceBarForLocale(isAutoCorrection);
updateSpacebarForLocale(isAutoCorrection);
return mSpaceKey;
}
private void updateSpaceBarForLocale(boolean isAutoCorrection) {
private void updateSpacebarForLocale(boolean isAutoCorrection) {
final Resources res = mContext.getResources();
// If application locales are explicitly selected.
if (SubtypeSwitcher.getInstance().needsToDisplayLanguage()) {
mSpaceKey.setIcon(new BitmapDrawable(res,
drawSpaceBar(OPACITY_FULLY_OPAQUE, isAutoCorrection)));
drawSpacebar(OPACITY_FULLY_OPAQUE, isAutoCorrection)));
} else {
// sym_keyboard_space_led can be shared with Black and White symbol themes.
if (isAutoCorrection) {
mSpaceKey.setIcon(new BitmapDrawable(res,
drawSpaceBar(OPACITY_FULLY_OPAQUE, isAutoCorrection)));
drawSpacebar(OPACITY_FULLY_OPAQUE, isAutoCorrection)));
} else {
mSpaceKey.setIcon(mSpaceIcon);
}
@ -128,8 +145,8 @@ public class LatinKeyboard extends Keyboard {
return bounds.width();
}
// Layout local language name and left and right arrow on space bar.
private static String layoutSpaceBar(Paint paint, Locale locale, Drawable lArrow,
// Layout local language name and left and right arrow on spacebar.
private static String layoutSpacebar(Paint paint, Locale locale, Drawable lArrow,
Drawable rArrow, int width, int height, float origTextSize,
boolean allowVariableTextSize) {
final float arrowWidth = lArrow.getIntrinsicWidth();
@ -138,7 +155,7 @@ public class LatinKeyboard extends Keyboard {
final Rect bounds = new Rect();
// 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);
// Assuming text width and text size are proportional to each other.
float textSize = origTextSize * Math.min(maxTextWidth / textWidth, 1.0f);
@ -171,8 +188,7 @@ public class LatinKeyboard extends Keyboard {
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 height = mSpaceIcon != null ? mSpaceIcon.getIntrinsicHeight() : mSpaceKey.mHeight;
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 String language = layoutSpaceBar(paint, subtypeSwitcher.getInputLocale(),
final String language = layoutSpacebar(paint, subtypeSwitcher.getInputLocale(),
mButtonArrowLeftIcon, mButtonArrowRightIcon, width, height,
getTextSizeFromTheme(textStyle, defaultTextSize),
allowVariableTextSize);
// 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();
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);
paint.setColor(res.getColor(R.color.latinkeyboard_bar_language_text));
paint.setColor(getSpacebarTextColor(mSpacebarTextColor, mSpacebarTextFadeFactor));
canvas.drawText(language, width / 2, baseline - descent, paint);
// 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) {
mButtonArrowLeftIcon.draw(canvas);
mButtonArrowRightIcon.draw(canvas);
@ -291,7 +311,6 @@ public class LatinKeyboard extends Keyboard {
* switching input languages.
*/
@Override
@SuppressWarnings("unused") // SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER is constant
public boolean isInside(Key key, int pointX, int pointY) {
int x = pointX;
int y = pointY;
@ -302,7 +321,7 @@ public class LatinKeyboard extends Keyboard {
if (code == CODE_DELETE) x -= key.mWidth / 6;
} else if (code == CODE_SPACE) {
y += LatinKeyboard.sSpacebarVerticalCorrection;
if (SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER
if (SubtypeSwitcher.getInstance().useSpacebarLanguageSwitcher()
&& SubtypeSwitcher.getInstance().getEnabledKeyboardLocaleCount() > 1) {
if (mCurrentlyInSpace) {
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
protected boolean onLongPress(Key key) {
int primaryCode = key.mCode;
@ -197,10 +205,10 @@ public class LatinKeyboardView extends KeyboardView {
@Override
public boolean onTouchEvent(MotionEvent me) {
LatinKeyboard keyboard = getLatinKeyboard();
if (keyboard == null) return true;
// If there was a sudden jump, return without processing the actual motion event.
if (handleSuddenJump(me))
return true;
if (handleSuddenJump(me)) return true;
// Reset any bounding box controls in the keyboard
if (me.getAction() == MotionEvent.ACTION_DOWN) {

View File

@ -71,7 +71,7 @@ public class MiniKeyboardBuilder {
for (CharSequence popupSpec : popupCharacters) {
final CharSequence label = PopupCharactersParser.getLabel(popupSpec.toString());
// 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) {
paint = new Paint();
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 BinaryDictionary sInstance = new BinaryDictionary();
private int mDicTypeId;
private int mNativeDict;
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 resId the resource containing the raw binary dictionary
* @return initialized instance of BinaryDictionary
*/
public BinaryDictionary(Context context, int resId, int dicTypeId) {
if (resId != 0) {
loadDictionary(context, resId);
public static BinaryDictionary initDictionary(Context context, int resId, int dicTypeId) {
synchronized (sInstance) {
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,
@ -104,6 +113,8 @@ public class BinaryDictionary extends Dictionary {
@Override
public void getBigrams(final WordComposer codes, final CharSequence previousWord,
final WordCallback callback, int[] nextLettersFrequencies) {
if (mNativeDict == 0) return;
char[] chars = previousWord.toString().toCharArray();
Arrays.fill(mOutputChars_bigrams, (char) 0);
Arrays.fill(mFrequencies_bigrams, 0);
@ -135,6 +146,8 @@ public class BinaryDictionary extends Dictionary {
@Override
public void getWords(final WordComposer codes, final WordCallback callback,
int[] nextLettersFrequencies) {
if (mNativeDict == 0) return;
final int codesSize = codes.size();
// Won't deal with really long words.
if (codesSize > MAX_WORD_LENGTH - 1) return;
@ -179,6 +192,10 @@ public class BinaryDictionary extends Dictionary {
@Override
public synchronized void close() {
closeInternal();
}
private void closeInternal() {
if (mNativeDict != 0) {
closeNative(mNativeDict);
mNativeDict = 0;
@ -188,7 +205,10 @@ public class BinaryDictionary extends Dictionary {
@Override
protected void finalize() throws Throwable {
close();
super.finalize();
try {
closeInternal();
} finally {
super.finalize();
}
}
}

View File

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

View File

@ -107,7 +107,7 @@ public class InputLanguageSelection extends PreferenceActivity {
res.updateConfiguration(conf, res.getDisplayMetrics());
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
// 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.KeyboardSwitcher;
import com.android.inputmethod.keyboard.KeyboardView;
import com.android.inputmethod.keyboard.LatinKeyboard;
import com.android.inputmethod.keyboard.LatinKeyboardView;
import com.android.inputmethod.latin.Utils.RingCharBuffer;
import com.android.inputmethod.voice.VoiceIMEConnector;
@ -132,14 +133,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private Resources mResources;
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 WordComposer mWord = new WordComposer();
private CharSequence mBestWord;
private boolean mHasValidSuggestions;
private boolean mIsSettingsSuggestionStripOn;
private boolean mApplicationSpecifiedCompletionOn;
private boolean mHasDictionary;
private boolean mAutoSpace;
private boolean mJustAddedAutoSpace;
private boolean mAutoCorrectEnabled;
private boolean mReCorrectionEnabled;
@ -151,6 +155,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private boolean mAutoCap;
private boolean mQuickFixes;
private boolean mConfigSwipeDownDismissKeyboardEnabled;
private int mConfigDelayBeforeFadeoutLanguageOnSpacebar;
private int mConfigDurationOfFadeoutLanguageOnSpacebar;
private float mConfigFinalFadeoutFactorOfLanguageOnSpacebar;
private int mCorrectionMode;
private int mCommittedLength;
@ -160,9 +167,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private int mLastSelectionEnd;
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
private boolean mJustAccepted;
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_SHIFT_STATE = 2;
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
public void handleMessage(Message msg) {
final KeyboardSwitcher switcher = mKeyboardSwitcher;
final LatinKeyboardView inputView = switcher.getInputView();
switch (msg.what) {
case MSG_UPDATE_SUGGESTIONS:
updateSuggestions();
@ -252,12 +260,24 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
setOldSuggestions();
break;
case MSG_UPDATE_SHIFT_STATE:
mKeyboardSwitcher.updateShiftState();
switcher.updateShiftState();
break;
case MSG_VOICE_RESULTS:
mVoiceConnector.handleVoiceResults(preferCapitalization()
|| (mKeyboardSwitcher.isAlphabetMode()
&& mKeyboardSwitcher.isShiftedOrShiftLocked()));
|| (switcher.isAlphabetMode() && switcher.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;
}
}
@ -297,6 +317,24 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
public void updateVoiceResults() {
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
@ -315,10 +353,24 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final Resources res = getResources();
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(
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();
boolean tryGC = true;
@ -360,7 +412,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mSuggest.close();
}
final SharedPreferences prefs = mPrefs;
mQuickFixes = prefs.getBoolean(Settings.PREF_QUICK_FIXES, true);
mQuickFixes = isQuickFixesEnabled(prefs);
final Resources res = mResources;
int mainDicResId = getMainDictionaryResourceId(res);
@ -402,27 +454,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public void onConfigurationChanged(Configuration conf) {
mSubtypeSwitcher.onConfigurationChanged(conf);
if (mSubtypeSwitcher.isKeyboardMode())
onKeyboardLanguageChanged();
updateAutoTextEnabled();
// If orientation changed while predicting, commit the change
if (conf.orientation != mOrientation) {
InputConnection ic = getCurrentInputConnection();
commitTyped(ic);
if (ic != null) ic.finishComposingText(); // For voice input
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;
super.onConfigurationChanged(conf);
mVoiceConnector.onConfigurationChanged(mConfigurationChanging);
mVoiceConnector.onConfigurationChanged(conf);
mConfigurationChanging = false;
}
@ -473,24 +515,62 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (mRefreshKeyboardRequired) {
mRefreshKeyboardRequired = false;
onKeyboardLanguageChanged();
onRefreshKeyboard();
}
TextEntryState.newSession(this);
// Most such things we decide below in the switch statement, but we need to know
// now whether this is a password text field, because we need to know now (before
// the switch statement) whether we want to enable the voice button.
int variation = attribute.inputType & InputType.TYPE_MASK_VARIATION;
mVoiceConnector.resetVoiceStates(isPasswordVariation(variation));
// Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
// know now whether this is a password text field, because we need to know now whether we
// want to enable the voice button.
mVoiceConnector.resetVoiceStates(isPasswordVariation(
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;
mIsSettingsSuggestionStripOn = false;
mApplicationSpecifiedCompletionOn = false;
mApplicationSpecifiedCompletions = null;
mEnteredText = null;
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_DATETIME:
mode = KeyboardId.MODE_NUMBER;
@ -525,7 +605,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mode = KeyboardId.MODE_WEB;
// If it's a browser edit field and auto correct is not ON explicitly, then
// 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;
}
} else {
@ -533,16 +613,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
// 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;
mInputTypeNoAutoCorrect = true;
}
// 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 &&
(attribute.inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 &&
(inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
mInputTypeNoAutoCorrect = true;
}
if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
mIsSettingsSuggestionStripOn = false;
mApplicationSpecifiedCompletionOn = isFullscreenMode();
}
@ -551,40 +631,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mode = KeyboardId.MODE_TEXT;
break;
}
inputView.closing();
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");
return mode;
}
private void checkReCorrectionOnStart() {
@ -1106,14 +1153,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private void handleBackspace() {
if (mVoiceConnector.logAndRevertVoiceInput()) return;
boolean deleteChar = false;
InputConnection ic = getCurrentInputConnection();
if (ic == null) return;
final InputConnection ic = getCurrentInputConnection();
if (ic == null) return;
ic.beginBatchEdit();
mVoiceConnector.handleBackspace();
boolean deleteChar = false;
if (mHasValidSuggestions) {
final int length = mComposing.length();
if (length > 0) {
@ -1131,12 +1178,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
deleteChar = true;
}
mHandler.postUpdateShiftKeyState();
TextEntryState.backspace();
if (TextEntryState.getState() == TextEntryState.State.UNDO_COMMIT) {
revertLastWord(deleteChar);
ic.endBatchEdit();
return;
} else if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) {
}
if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) {
ic.deleteSurroundingText(mEnteredText.length(), 0);
} else if (deleteChar) {
if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
@ -1355,7 +1405,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
private boolean isSuggestionsRequested() {
return mIsSettingsSuggestionStripOn;
return mIsSettingsSuggestionStripOn
&& (mCorrectionMode > 0 || isShowingSuggestionsStrip());
}
private boolean isShowingPunctuationList() {
@ -1491,7 +1542,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) {
setSuggestions(suggestedWords);
if (suggestedWords.size() > 0) {
if (suggestedWords.hasAutoCorrectionWord()) {
if (Utils.shouldBlockedBySafetyNetForAutoCorrection(suggestedWords)) {
mBestWord = typedWord;
} else if (suggestedWords.hasAutoCorrectionWord()) {
mBestWord = suggestedWords.getWord(1);
} else {
mBestWord = typedWord;
@ -1773,18 +1826,31 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final int length = mComposing.length();
if (!mHasValidSuggestions && length > 0) {
final InputConnection ic = getCurrentInputConnection();
mHasValidSuggestions = true;
mJustReverted = true;
final CharSequence punctuation = ic.getTextBeforeCursor(1, 0);
if (deleteChar) ic.deleteSurroundingText(1, 0);
int toDelete = mCommittedLength;
CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0);
if (toTheLeft != null && toTheLeft.length() > 0
&& isWordSeparator(toTheLeft.charAt(0))) {
final CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0);
if (!TextUtils.isEmpty(toTheLeft) && isWordSeparator(toTheLeft.charAt(0))) {
toDelete--;
}
ic.deleteSurroundingText(toDelete, 0);
ic.setComposingText(mComposing, 1);
TextEntryState.backspace();
// Re-insert punctuation only when the deleted character was word separator and the
// 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();
} else {
sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
@ -1814,21 +1880,22 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return mWord.isFirstCharCapitalized();
}
// Notify that Language has been changed and toggleLanguage will update KeyboaredID according
// to new Language.
public void onKeyboardLanguageChanged() {
// Notify that language or mode have been changed and toggleLanguage will update KeyboaredID
// according to new language or mode.
public void onRefreshKeyboard() {
toggleLanguage(true, true);
}
// "reset" and "next" are used only for USE_SPACEBAR_LANGUAGE_SWITCHER.
private void toggleLanguage(boolean reset, boolean next) {
if (SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER) {
if (mSubtypeSwitcher.useSpacebarLanguageSwitcher()) {
mSubtypeSwitcher.toggleLanguage(reset, next);
}
// Reload keyboard because the current language has been changed.
KeyboardSwitcher switcher = mKeyboardSwitcher;
final int mode = switcher.getKeyboardMode();
final EditorInfo attribute = getCurrentInputEditorInfo();
final int mode = initializeInputAttributesAndGetMode((attribute != null)
? attribute.inputType : 0);
final int imeOptions = (attribute != null) ? attribute.imeOptions : 0;
switcher.loadKeyboard(mode, imeOptions, mVoiceConnector.isVoiceButtonEnabled(),
mVoiceConnector.isVoiceButtonOnPrimary());
@ -2016,7 +2083,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mPopupOn = prefs.getBoolean(Settings.PREF_POPUP_ON,
mResources.getBoolean(R.bool.config_default_popup_preview));
mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true);
mQuickFixes = prefs.getBoolean(Settings.PREF_QUICK_FIXES, true);
mQuickFixes = isQuickFixesEnabled(prefs);
mAutoCorrectEnabled = isAutoCorrectEnabled(prefs);
mBigramSuggestionEnabled = mAutoCorrectEnabled && isBigramSuggestionEnabled(prefs);
@ -2065,6 +2132,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
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) {
final String currentAutoCorrectionSetting = sp.getString(
Settings.PREF_AUTO_CORRECTION_THRESHOLD,
@ -2075,8 +2152,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
private boolean isBigramSuggestionEnabled(SharedPreferences sp) {
// TODO: Define default value instead of 'true'.
return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, true);
final boolean showBigramSuggestionsOption = mResources.getBoolean(
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() {

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
@ -48,6 +48,7 @@ public class Settings extends PreferenceActivity
DialogInterface.OnDismissListener, OnPreferenceClickListener {
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_SOUND_ON = "sound_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_BIGRAM_SUGGESTIONS = "bigram_suggestion";
public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode";
// Dialog ids
private static final int VOICE_INPUT_CONFIRM_DIALOG = 0;
@ -111,30 +114,64 @@ public class Settings extends PreferenceActivity
mBigramSuggestion = (CheckBoxPreference) findPreference(PREF_BIGRAM_SUGGESTIONS);
ensureConsistencyOfAutoCorrectionSettings();
final PreferenceGroup generalSettings =
(PreferenceGroup) findPreference(PREF_GENERAL_SETTINGS_KEY);
final PreferenceGroup textCorrectionGroup =
(PreferenceGroup) findPreference(PREF_PREDICTION_SETTINGS_KEY);
final boolean showSettingsKeyOption = getResources().getBoolean(
R.bool.config_enable_show_settings_key_option);
if (!showSettingsKeyOption) {
getPreferenceScreen().removePreference(mSettingsKeyPreference);
generalSettings.removePreference(mSettingsKeyPreference);
}
final boolean showVoiceKeyOption = getResources().getBoolean(
R.bool.config_enable_show_voice_key_option);
if (!showVoiceKeyOption) {
getPreferenceScreen().removePreference(mVoicePreference);
generalSettings.removePreference(mVoicePreference);
}
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
if (vibrator == null
// @@@ || !vibrator.hasVibrator()
) {
getPreferenceScreen().removePreference(
getPreferenceScreen().findPreference(PREF_VIBRATE_ON));
generalSettings.removePreference(findPreference(PREF_VIBRATE_ON));
}
final boolean showSubtypeSettings = getResources().getBoolean(
R.bool.config_enable_show_subtype_settings);
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) {
final String action;
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";
} else {
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;
import com.android.inputmethod.compat.InputMethodSubtype;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.voice.SettingsUtil;
import com.android.inputmethod.voice.VoiceIMEConnector;
@ -40,11 +41,6 @@ import java.util.Locale;
import java.util.Map;
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 String TAG = "SubtypeSwitcher";
@ -63,6 +59,8 @@ public class SubtypeSwitcher {
new ArrayList<InputMethodSubtype>();
private final ArrayList<String> mEnabledLanguagesOfCurrentInputMethod = new ArrayList<String>();
private boolean mConfigUseSpacebarLanguageSwitcher;
/*-----------------------------------------------------------*/
// Variants which should be changed only by reload functions.
private boolean mNeedsToDisplayLanguage;
@ -84,11 +82,9 @@ public class SubtypeSwitcher {
public static void init(LatinIME service, SharedPreferences prefs) {
sInstance.mPrefs = prefs;
sInstance.resetParams(service);
if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
sInstance.initLanguageSwitcher(service);
}
sInstance.updateAllParameters();
SubtypeLocale.init(service);
}
private SubtypeSwitcher() {
@ -109,6 +105,10 @@ public class SubtypeSwitcher {
mAllEnabledSubtypesOfCurrentInputMethod = null;
// TODO: Voice input should be created here
mVoiceInput = null;
mConfigUseSpacebarLanguageSwitcher = mResources.getBoolean(
R.bool.config_use_spacebar_language_switcher);
if (mConfigUseSpacebarLanguageSwitcher)
initLanguageSwitcher(service);
}
// 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
// should be updated every time onStartInputview.
public void updateParametersOnStartInputView() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
updateForSpaceBarLanguageSwitch();
if (mConfigUseSpacebarLanguageSwitcher) {
updateForSpacebarLanguageSwitch();
} else {
updateEnabledSubtypes();
}
@ -134,7 +134,7 @@ public class SubtypeSwitcher {
private void updateEnabledSubtypes() {
boolean foundCurrentSubtypeBecameDisabled = true;
// @@@ mAllEnabledSubtypesOfCurrentInputMethod = mImm.getEnabledInputMethodSubtypeList(
//null, false);
// null, true);
mEnabledLanguagesOfCurrentInputMethod.clear();
mEnabledKeyboardSubtypesOfCurrentInputMethod.clear();
for (InputMethodSubtype ims: mAllEnabledSubtypesOfCurrentInputMethod) {
@ -155,6 +155,7 @@ public class SubtypeSwitcher {
&& mIsSystemLanguageSameAsInputLanguage);
if (foundCurrentSubtypeBecameDisabled) {
if (DBG) {
Log.w(TAG, "Current subtype: " + mInputLocaleStr + ", " + mMode);
Log.w(TAG, "Last subtype was disabled. Update to the current one.");
}
// @@@ updateSubtype(mImm.getCurrentInputMethodSubtype());
@ -188,7 +189,7 @@ public class SubtypeSwitcher {
// fallback to the default locale and mode.
Log.w(TAG, "Couldn't get the current subtype.");
newLocale = "en_US";
newMode =KEYBOARD_MODE;
newMode = KEYBOARD_MODE;
} else {
newLocale = newSubtype.getLocale();
newMode = newSubtype.getMode();
@ -218,8 +219,8 @@ public class SubtypeSwitcher {
mVoiceInput.cancel();
}
}
if (languageChanged) {
mService.onKeyboardLanguageChanged();
if (modeChanged || languageChanged) {
mService.onRefreshKeyboard();
}
} else if (isVoiceMode()) {
// If needsToShowWarningDialog is true, voice input need to show warning before
@ -311,19 +312,23 @@ public class SubtypeSwitcher {
//////////////////////////////////
public int getEnabledKeyboardLocaleCount() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
if (mConfigUseSpacebarLanguageSwitcher) {
return mLanguageSwitcher.getLocaleCount();
} else {
return mEnabledKeyboardSubtypesOfCurrentInputMethod.size();
}
}
public boolean useSpacebarLanguageSwitcher() {
return mConfigUseSpacebarLanguageSwitcher;
}
public boolean needsToDisplayLanguage() {
return mNeedsToDisplayLanguage;
}
public Locale getInputLocale() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
if (mConfigUseSpacebarLanguageSwitcher) {
return mLanguageSwitcher.getInputLocale();
} else {
return mInputLocale;
@ -331,7 +336,7 @@ public class SubtypeSwitcher {
}
public String getInputLocaleStr() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
if (mConfigUseSpacebarLanguageSwitcher) {
String inputLanguage = null;
inputLanguage = mLanguageSwitcher.getInputLanguage();
// Should return system locale if there is no Language available.
@ -345,7 +350,7 @@ public class SubtypeSwitcher {
}
public String[] getEnabledLanguages() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
if (mConfigUseSpacebarLanguageSwitcher) {
return mLanguageSwitcher.getEnabledLanguages();
} else {
return mEnabledLanguagesOfCurrentInputMethod.toArray(
@ -354,7 +359,7 @@ public class SubtypeSwitcher {
}
public Locale getSystemLocale() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
if (mConfigUseSpacebarLanguageSwitcher) {
return mLanguageSwitcher.getSystemLocale();
} else {
return mSystemLocale;
@ -362,7 +367,7 @@ public class SubtypeSwitcher {
}
public boolean isSystemLanguageSameAsInputLanguage() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
if (mConfigUseSpacebarLanguageSwitcher) {
return getSystemLocale().getLanguage().equalsIgnoreCase(
getInputLocaleStr().substring(0, 2));
} else {
@ -374,7 +379,7 @@ public class SubtypeSwitcher {
final Locale systemLocale = conf.locale;
// If system configuration was changed, update all parameters.
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
// locale (mSystemLocale), then reload the input locale list from the
// latin ime settings (shared prefs) and reset the input locale
@ -388,7 +393,7 @@ public class SubtypeSwitcher {
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
if (mConfigUseSpacebarLanguageSwitcher) {
if (Settings.PREF_SELECTED_LANGUAGES.equals(key)) {
mLanguageSwitcher.loadLocales(sharedPreferences);
}
@ -438,18 +443,18 @@ public class SubtypeSwitcher {
private void triggerVoiceIME() {
if (!mService.isInputViewShown()) return;
VoiceIMEConnector.getInstance().startListening(false,
KeyboardSwitcher.getInstance().getInputView().getWindowToken(), false);
KeyboardSwitcher.getInstance().getInputView().getWindowToken());
}
//////////////////////////////////////
// SpaceBar Language Switch support //
// Spacebar Language Switch support //
//////////////////////////////////////
private LanguageSwitcher mLanguageSwitcher;
public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) {
if (returnsNameInThisLocale) {
return toTitleCase(locale.getDisplayName(locale));
return toTitleCase(SubtypeLocale.getFullDisplayName(locale));
} else {
return toTitleCase(locale.getDisplayName());
}
@ -470,7 +475,7 @@ public class SubtypeSwitcher {
return Character.toUpperCase(s.charAt(0)) + s.substring(1);
}
private void updateForSpaceBarLanguageSwitch() {
private void updateForSpacebarLanguageSwitch() {
// We need to update mNeedsToDisplayLanguage in onStartInputView because
// getEnabledKeyboardLocaleCount could have been changed.
mNeedsToDisplayLanguage = !(getEnabledKeyboardLocaleCount() <= 1
@ -483,7 +488,7 @@ public class SubtypeSwitcher {
}
public String getNextInputLanguageName() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
if (mConfigUseSpacebarLanguageSwitcher) {
return getDisplayLanguage(mLanguageSwitcher.getNextInputLocale());
} else {
return "";
@ -491,7 +496,7 @@ public class SubtypeSwitcher {
}
public String getPreviousInputLanguageName() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
if (mConfigUseSpacebarLanguageSwitcher) {
return getDisplayLanguage(mLanguageSwitcher.getPrevInputLocale());
} else {
return "";
@ -528,13 +533,13 @@ public class SubtypeSwitcher {
}
public void loadSettings() {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
if (mConfigUseSpacebarLanguageSwitcher) {
mLanguageSwitcher.loadLocales(mPrefs);
}
}
public void toggleLanguage(boolean reset, boolean next) {
if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
if (mConfigUseSpacebarLanguageSwitcher) {
if (reset) {
mLanguageSwitcher.reset();
} else {

View File

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

View File

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

View File

@ -36,6 +36,8 @@ import java.text.SimpleDateFormat;
import java.util.Date;
public class Utils {
private static final String TAG = Utils.class.getSimpleName();
private static boolean DBG = LatinImeLogger.sDBG;
/**
* Cancel an {@link AsyncTask}.
@ -96,6 +98,29 @@ public class Utils {
// || 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 {
private static RingCharBuffer sRingCharBuffer = new RingCharBuffer();
private static final char PLACEHOLDER_DELIMITER_CHAR = '\uFFFC';

View File

@ -16,9 +16,6 @@
package com.android.inputmethod.voice;
import com.android.inputmethod.latin.R;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
@ -29,20 +26,21 @@ import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.TypedValue;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.MarginLayoutParams;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.android.inputmethod.latin.R;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
import java.util.ArrayList;
import java.util.List;
/**
@ -58,81 +56,55 @@ public class RecognitionView {
private View mView;
private Context mContext;
private ImageView mImage;
private TextView mText;
private View mButton;
private TextView mButtonText;
private ImageView mImage;
private View mProgress;
private SoundIndicator mSoundIndicator;
private Button mButton;
private Drawable mInitializing;
private Drawable mError;
private List<Drawable> mSpeakNow;
private float mVolume = 0.0f;
private int mLevel = 0;
private static final int INIT = 0;
private static final int LISTENING = 1;
private static final int WORKING = 2;
private static final int READY = 3;
private int mState = INIT;
private enum State {LISTENING, WORKING, READY}
private State mState = State.READY;
private final View mPopupLayout;
private float mMinMicrophoneLevel;
private float mMaxMicrophoneLevel;
/** 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);
}
};
private final Drawable mListeningBorder;
private final Drawable mWorkingBorder;
private final Drawable mErrorBorder;
public RecognitionView(Context context, OnClickListener clickListener) {
mUiHandler = new Handler();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
Context.LAYOUT_INFLATER_SERVICE);
mView = inflater.inflate(R.layout.recognition_status, null);
ContentResolver cr = context.getContentResolver();
mMinMicrophoneLevel = SettingsUtil.getSettingsFloat(
cr, SettingsUtil.LATIN_IME_MIN_MICROPHONE_LEVEL, 15.f);
mMaxMicrophoneLevel = SettingsUtil.getSettingsFloat(
cr, SettingsUtil.LATIN_IME_MAX_MICROPHONE_LEVEL, 30.f);
mPopupLayout= mView.findViewById(R.id.popup_layout);
// Pre-load volume level images
Resources r = context.getResources();
mSpeakNow = new ArrayList<Drawable>();
mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level0));
mSpeakNow.add(r.getDrawable(R.drawable.speak_now_level1));
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));
mListeningBorder = r.getDrawable(R.drawable.vs_dialog_red);
mWorkingBorder = r.getDrawable(R.drawable.vs_dialog_blue);
mErrorBorder = r.getDrawable(R.drawable.vs_dialog_yellow);
mInitializing = r.getDrawable(R.drawable.mic_slash);
mError = r.getDrawable(R.drawable.caution);
mImage = (ImageView) mView.findViewById(R.id.image);
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);
mText = (TextView) mView.findViewById(R.id.text);
mButtonText = (TextView) mView.findViewById(R.id.button_text);
mProgress = mView.findViewById(R.id.progress);
mContext = context;
}
@ -146,9 +118,9 @@ public class RecognitionView {
@Override
public void run() {
// Restart the spinner
if (mState == State.WORKING) {
((ProgressBar)mProgress).setIndeterminate(false);
((ProgressBar)mProgress).setIndeterminate(true);
if (mState == WORKING) {
((ProgressBar) mProgress).setIndeterminate(false);
((ProgressBar) mProgress).setIndeterminate(true);
}
}
});
@ -158,48 +130,48 @@ public class RecognitionView {
mUiHandler.post(new Runnable() {
@Override
public void run() {
prepareDialog(false, mContext.getText(R.string.voice_initializing), mInitializing,
mContext.getText(R.string.cancel));
mState = INIT;
prepareDialog(mContext.getText(R.string.voice_initializing), mInitializing,
mContext.getText(R.string.cancel));
}
});
}
public void showListening() {
Log.d(TAG, "#showListening");
mUiHandler.post(new Runnable() {
@Override
public void run() {
mState = State.LISTENING;
prepareDialog(false, mContext.getText(R.string.voice_listening), mSpeakNow.get(0),
mState = LISTENING;
prepareDialog(mContext.getText(R.string.voice_listening), null,
mContext.getText(R.string.cancel));
}
});
mUiHandler.postDelayed(mUpdateVolumeRunnable, 50);
}
public void updateVoiceMeter(final float rmsdB) {
mVolume = rmsdB;
public void updateVoiceMeter(float rmsdB) {
mSoundIndicator.setRmsdB(rmsdB);
}
public void showError(final String message) {
mUiHandler.post(new Runnable() {
@Override
public void run() {
mState = State.READY;
prepareDialog(false, message, mError, mContext.getText(R.string.ok));
mState = READY;
prepareDialog(message, mError, mContext.getText(R.string.ok));
}
});
});
}
public void showWorking(
final ByteArrayOutputStream waveBuffer,
final int speechStartPosition,
final int speechEndPosition) {
mUiHandler.post(new Runnable() {
@Override
public void run() {
mState = State.WORKING;
prepareDialog(true, mContext.getText(R.string.voice_working), null, mContext
mState = WORKING;
prepareDialog(mContext.getText(R.string.voice_working), null, mContext
.getText(R.string.cancel));
final ShortBuffer buf = ByteBuffer.wrap(waveBuffer.toByteArray()).order(
ByteOrder.nativeOrder()).asShortBuffer();
@ -207,21 +179,71 @@ public class RecognitionView {
waveBuffer.reset();
showWave(buf, speechStartPosition / 2, speechEndPosition / 2);
}
});
});
}
private void prepareDialog(boolean spinVisible, CharSequence text, Drawable image,
private void prepareDialog(CharSequence text, Drawable image,
CharSequence btnTxt) {
if (spinVisible) {
mProgress.setVisibility(View.VISIBLE);
mImage.setVisibility(View.GONE);
} else {
mProgress.setVisibility(View.GONE);
mImage.setImageDrawable(image);
mImage.setVisibility(View.VISIBLE);
switch (mState) {
case INIT:
mText.setVisibility(View.GONE);
mProgress.setVisibility(View.GONE);
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);
mButtonText.setText(btnTxt);
mPopupLayout.requestLayout();
mButton.setText(btnTxt);
}
/**
@ -248,7 +270,7 @@ public class RecognitionView {
*/
private void showWave(ShortBuffer waveBuffer, int startPosition, int endPosition) {
final int w = ((View) mImage.getParent()).getWidth();
final int h = mImage.getHeight();
final int h = ((View) mImage.getParent()).getHeight();
if (w <= 0 || h <= 0) {
// view is not visible this time. Skip drawing.
return;
@ -259,7 +281,7 @@ public class RecognitionView {
paint.setColor(0xFFFFFFFF); // 0xAARRGGBB
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setAlpha(0x90);
paint.setAlpha(80);
final PathEffect effect = new CornerPathEffect(3);
paint.setPathEffect(effect);
@ -281,7 +303,7 @@ public class RecognitionView {
final int count = (endIndex - startIndex) / numSamplePerWave;
final float deltaX = 1.0f * w / count;
int yMax = h / 2 - 8;
int yMax = h / 2;
Path path = new Path();
c.translate(0, yMax);
float x = 0;
@ -295,37 +317,20 @@ public class RecognitionView {
path.lineTo(x, y);
}
if (deltaX > 4) {
paint.setStrokeWidth(3);
paint.setStrokeWidth(2);
} else {
paint.setStrokeWidth(Math.max(1, (int) (deltaX -.05)));
paint.setStrokeWidth(Math.max(0, (int) (deltaX -.05)));
}
c.drawPath(path, paint);
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() {
mUiHandler.post(new Runnable() {
@Override
public void run() {
mState = State.READY;
exitWorking();
mSoundIndicator.stop();
}
});
}
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;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.latin.EditingUtils;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.LatinIME.UIHandler;
@ -29,6 +30,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.IBinder;
import android.preference.PreferenceManager;
@ -77,6 +79,9 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
// dialog is already showing a voice search button.
private static final String IME_OPTION_NO_MICROPHONE = "nm";
@SuppressWarnings("unused")
private static final String TAG = "VoiceIMEConnector";
private boolean mAfterVoiceInput;
private boolean mHasUsedVoiceInput;
private boolean mHasUsedVoiceInputUnsupportedLocale;
@ -91,7 +96,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
private boolean mVoiceInputHighlighted;
private InputMethodManager mImm;
private LatinIME mContext;
private LatinIME mService;
private AlertDialog mVoiceWarningDialog;
private VoiceInput mVoiceInput;
private final VoiceResults mVoiceResults = new VoiceResults();
@ -111,21 +116,19 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
return sInstance;
}
private void initInternal(LatinIME context, SharedPreferences prefs, UIHandler h) {
mContext = context;
private void initInternal(LatinIME service, SharedPreferences prefs, UIHandler h) {
mService = service;
mHandler = h;
mImm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
mImm = (InputMethodManager) service.getSystemService(Context.INPUT_METHOD_SERVICE);
mSubtypeSwitcher = SubtypeSwitcher.getInstance();
if (VOICE_INSTALLED) {
mVoiceInput = new VoiceInput(context, this);
mHints = new Hints(context, prefs, new Hints.Display() {
mVoiceInput = new VoiceInput(service, this);
mHints = new Hints(service, prefs, new Hints.Display() {
@Override
public void showHint(int viewResource) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(viewResource, null);
mContext.setCandidatesView(view);
mContext.setCandidatesViewShown(true);
View view = LayoutInflater.from(mService).inflate(viewResource, null);
mService.setCandidatesView(view);
mService.setCandidatesViewShown(true);
mIsShowingHint = true;
}
});
@ -161,23 +164,22 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
mVoiceInput.flushAllTextModificationCounters();
// send this intent AFTER logging any prior aggregated edits.
mVoiceInput.logTextModifiedByChooseSuggestion(suggestion.toString(), index,
wordSeparators, mContext.getCurrentInputConnection());
wordSeparators, mService.getCurrentInputConnection());
}
}
private void showVoiceWarningDialog(final boolean swipe, IBinder token,
final boolean configurationChanging) {
private void showVoiceWarningDialog(final boolean swipe, IBinder token) {
if (mVoiceWarningDialog != null && mVoiceWarningDialog.isShowing()) {
return;
}
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
AlertDialog.Builder builder = new AlertDialog.Builder(mService);
builder.setCancelable(true);
builder.setIcon(R.drawable.ic_mic_dialog);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
mVoiceInput.logKeyboardWarningDialogOk();
reallyStartListening(swipe, configurationChanging);
reallyStartListening(swipe);
}
});
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@ -199,13 +201,13 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
final CharSequence message;
if (mLocaleSupportedForVoiceInput) {
message = TextUtils.concat(
mContext.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_may_not_understand), "\n\n",
mService.getText(R.string.voice_warning_how_to_turn_off));
} else {
message = TextUtils.concat(
mContext.getText(R.string.voice_warning_locale_not_supported), "\n\n",
mContext.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_locale_not_supported), "\n\n",
mService.getText(R.string.voice_warning_may_not_understand), "\n\n",
mService.getText(R.string.voice_warning_how_to_turn_off));
}
builder.setMessage(message);
@ -296,7 +298,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
}
public void showPunctuationHintIfNecessary() {
InputConnection ic = mContext.getCurrentInputConnection();
InputConnection ic = mService.getCurrentInputConnection();
if (!mImmediatelyAfterVoiceInput && mAfterVoiceInput && ic != null) {
if (mHints.showPunctuationHintIfNecessary(ic)) {
mVoiceInput.logPunctuationHintDisplayed();
@ -364,17 +366,17 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
}
private void revertVoiceInput() {
InputConnection ic = mContext.getCurrentInputConnection();
InputConnection ic = mService.getCurrentInputConnection();
if (ic != null) ic.commitText("", 1);
mContext.updateSuggestions();
mService.updateSuggestions();
mVoiceInputHighlighted = false;
}
public void commitVoiceInput() {
if (VOICE_INSTALLED && mVoiceInputHighlighted) {
InputConnection ic = mContext.getCurrentInputConnection();
InputConnection ic = mService.getCurrentInputConnection();
if (ic != null) ic.finishComposingText();
mContext.updateSuggestions();
mService.updateSuggestions();
mVoiceInputHighlighted = false;
}
}
@ -394,7 +396,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
if (mShowingVoiceSuggestions) {
// Retain the replaced word in the alternatives array.
String wordToBeReplaced = EditingUtils.getWordAtCursor(
mContext.getCurrentInputConnection(), wordSeparators);
mService.getCurrentInputConnection(), wordSeparators);
if (!mWordToSuggestions.containsKey(wordToBeReplaced)) {
wordToBeReplaced = wordToBeReplaced.toLowerCase();
}
@ -438,8 +440,8 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
builder.addWords(suggestions);
}
builder.setTypedWordValid(true).setHasMinimalSuggestion(true);
mContext.setSuggestions(builder.build());
mContext.setCandidatesViewShown(true);
mService.setSuggestions(builder.build());
mService.setCandidatesViewShown(true);
return true;
}
return false;
@ -486,15 +488,15 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
mAfterVoiceInput = true;
mImmediatelyAfterVoiceInput = true;
InputConnection ic = mContext.getCurrentInputConnection();
if (!mContext.isFullscreenMode()) {
InputConnection ic = mService.getCurrentInputConnection();
if (!mService.isFullscreenMode()) {
// Start listening for updates to the text from typing, etc.
if (ic != null) {
ExtractedTextRequest req = new ExtractedTextRequest();
ic.getExtractedText(req, InputConnection.GET_EXTRACTED_TEXT_MONITOR);
}
}
mContext.vibrate();
mService.vibrate();
final List<CharSequence> nBest = new ArrayList<CharSequence>();
for (String c : mVoiceResults.candidates) {
@ -511,7 +513,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
mHints.registerVoiceResult(bestResult);
if (ic != null) ic.beginBatchEdit(); // To avoid extra updates on committing older text
mContext.commitTyped(ic);
mService.commitTyped(ic);
EditingUtils.appendText(ic, bestResult);
if (ic != null) ic.endBatchEdit();
@ -520,22 +522,38 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
onCancelVoice();
}
public void switchToRecognitionStatusView(final boolean configurationChanging) {
final boolean configChanged = configurationChanging;
public void switchToRecognitionStatusView(final Configuration configuration) {
mHandler.post(new Runnable() {
@Override
public void run() {
mContext.setCandidatesViewShown(false);
mService.setCandidatesViewShown(false);
mRecognizing = true;
mVoiceInput.newView();
View v = mVoiceInput.getView();
ViewParent p = v.getParent();
if (p != null && p instanceof ViewGroup) {
((ViewGroup)p).removeView(v);
((ViewGroup) p).removeView(v);
}
mContext.setInputView(v);
mContext.updateInputViewShown();
if (configChanged) {
mVoiceInput.onConfigurationChanged();
View keyboardView = KeyboardSwitcher.getInstance().getInputView();
// 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) {
return;
}
@ -555,7 +573,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
// The user has started a voice input, so remember that in the
// future (so we don't show the warning dialog after the first run).
SharedPreferences.Editor editor =
PreferenceManager.getDefaultSharedPreferences(mContext).edit();
PreferenceManager.getDefaultSharedPreferences(mService).edit();
editor.putBoolean(PREF_HAS_USED_VOICE_INPUT, true);
SharedPreferencesCompat.apply(editor);
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
// in the future (so we don't show the warning dialog the next time they do this).
SharedPreferences.Editor editor =
PreferenceManager.getDefaultSharedPreferences(mContext).edit();
PreferenceManager.getDefaultSharedPreferences(mService).edit();
editor.putBoolean(PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE, true);
SharedPreferencesCompat.apply(editor);
mHasUsedVoiceInputUnsupportedLocale = true;
}
// Clear N-best suggestions
mContext.clearSuggestions();
mService.clearSuggestions();
FieldContext context = makeFieldContext();
mVoiceInput.startListening(context, swipe);
switchToRecognitionStatusView(configurationChanging);
switchToRecognitionStatusView(null);
}
public void startListening(final boolean swipe, IBinder token,
final boolean configurationChanging) {
public void startListening(final boolean swipe, IBinder token) {
// TODO: remove swipe which is no longer used.
if (VOICE_INSTALLED) {
if (needsToShowWarningDialog()) {
// Calls reallyStartListening if user clicks OK, does nothing if user clicks Cancel.
showVoiceWarningDialog(swipe, token, configurationChanging);
showVoiceWarningDialog(swipe, token);
} else {
reallyStartListening(swipe, configurationChanging);
reallyStartListening(swipe);
}
}
}
private boolean fieldCanDoVoice(FieldContext fieldContext) {
return !mPasswordText
&& mVoiceInput != null
@ -603,7 +619,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
return ENABLE_VOICE_BUTTON && fieldCanDoVoice(fieldContext)
&& !(attribute != null
&& IME_OPTION_NO_MICROPHONE.equals(attribute.privateImeOptions))
&& SpeechRecognizer.isRecognitionAvailable(mContext);
&& SpeechRecognizer.isRecognitionAvailable(mService);
}
public void loadSettings(EditorInfo attribute, SharedPreferences sp) {
@ -616,10 +632,10 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
if (VOICE_INSTALLED) {
final String voiceMode = sp.getString(PREF_VOICE_MODE,
mContext.getString(R.string.voice_mode_main));
mVoiceButtonEnabled = !voiceMode.equals(mContext.getString(R.string.voice_mode_off))
mService.getString(R.string.voice_mode_main));
mVoiceButtonEnabled = !voiceMode.equals(mService.getString(R.string.voice_mode_off))
&& 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) {
// If IME is in voice mode, but still needs to show the voice warning dialog,
// keep showing the warning.
if (mSubtypeSwitcher.isVoiceMode() && needsToShowWarningDialog() && token != null) {
showVoiceWarningDialog(false, token, false);
if (mSubtypeSwitcher.isVoiceMode() && token != null) {
// 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() {
@ -643,9 +664,9 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
mSubtypeSwitcher.setVoiceInput(mVoiceInput);
}
public void onConfigurationChanged(boolean configurationChanging) {
public void onConfigurationChanged(Configuration configuration) {
if (mRecognizing) {
switchToRecognitionStatusView(configurationChanging);
switchToRecognitionStatusView(configuration);
}
}
@ -664,7 +685,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
// onCurrentInputMethodSubtypeChanged() will be called first. LatinIME will know
// that it's in keyboard mode and SubtypeSwitcher will call onCancelVoice().
mRecognizing = false;
mContext.switchToKeyboardView();
mService.switchToKeyboardView();
}
}
}
@ -682,8 +703,8 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
public FieldContext makeFieldContext() {
SubtypeSwitcher switcher = SubtypeSwitcher.getInstance();
return new FieldContext(mContext.getCurrentInputConnection(),
mContext.getCurrentInputEditorInfo(), switcher.getInputLocaleStr(),
return new FieldContext(mService.getCurrentInputConnection(),
mService.getCurrentInputEditorInfo(), switcher.getInputLocaleStr(),
switcher.getEnabledLanguages());
}

View File

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

View File

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