diff options
Diffstat (limited to 'java')
98 files changed, 2934 insertions, 1976 deletions
diff --git a/java/res/values-et/donottranslate-more-keys.xml b/java/res/values-et/donottranslate-more-keys.xml new file mode 100644 index 000000000..d6b3099ad --- /dev/null +++ b/java/res/values-et/donottranslate-more-keys.xml @@ -0,0 +1,37 @@ +<?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. +*/ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="more_keys_for_a">ä,ā,à,á,â,ã,å,æ,ą</string> + <string name="more_keys_for_e">3,ē,è,ė,é,ê,ë,ę,ě</string> + <string name="more_keys_for_i">8,ī,ì,į,í,î,ï,ı</string> + <string name="more_keys_for_o">9,ö,õ,ò,ó,ô,œ,ő,ø</string> + <string name="more_keys_for_u">7,ü,ū,ų,ù,ú,û,ů,ű</string> + <string name="more_keys_for_s">š,ß,ś,ş</string> + <string name="more_keys_for_n">ņ,ñ,ń,ń</string> + <string name="more_keys_for_c">č,ç,ć</string> + <string name="more_keys_for_y">6,ý,ÿ</string> + <string name="more_keys_for_d">ď</string> + <string name="more_keys_for_r">4,ŗ,ř,ŕ</string> + <string name="more_keys_for_t">5,ţ,ť</string> + <string name="more_keys_for_z">ž,ż,ź</string> + <string name="more_keys_for_k">ķ</string> + <string name="more_keys_for_l">ļ,ł,ĺ,ľ</string> + <string name="more_keys_for_g">ģ,ğ</string> +</resources> diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml index 7b89edd54..ef9303e88 100644 --- a/java/res/values-fr/strings.xml +++ b/java/res/values-fr/strings.xml @@ -35,8 +35,8 @@ <string name="misc_category" msgid="6894192814868233453">"Autres options"</string> <string name="advanced_settings" msgid="362895144495591463">"Paramètres avancés"</string> <string name="advanced_settings_summary" msgid="5193513161106637254">"Options destinées aux utilisateurs expérimentés"</string> - <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Masquer touche agrandie"</string> - <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sans délai"</string> + <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Délai masq. touche pop-up"</string> + <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Aucun délai"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Par défaut"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Proposer noms de contacts"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utiliser des noms de contacts pour les suggestions et corrections"</string> @@ -51,7 +51,7 @@ <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Afficher en mode Portrait"</string> <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Toujours masquer"</string> <string name="prefs_settings_key" msgid="4623341240804046498">"Afficher touche param."</string> - <string name="auto_correction" msgid="4979925752001319458">"Correction automatique"</string> + <string name="auto_correction" msgid="4979925752001319458">"Correction auto."</string> <string name="auto_correction_summary" msgid="5625751551134658006">"Corriger autom. orthographe (pression sur barre espace/signes ponctuation)"</string> <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Désactiver"</string> <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Simple"</string> @@ -132,7 +132,7 @@ <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Sur clavier principal"</string> <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Sur clavier symboles"</string> <string name="voice_input_modes_off" msgid="3745699748218082014">"Désactiver"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Micro sur le clavier principal"</string> + <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Micro clavier principal"</string> <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Micro sur clavier symboles"</string> <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Saisie vocale désactivée"</string> <string name="selectInputMethod" msgid="315076553378705821">"Sélectionner un mode de saisie."</string> @@ -148,6 +148,6 @@ <string name="subtype_en_GB" msgid="88170601942311355">"Anglais (Royaume-Uni)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Anglais (États-Unis)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Mode d\'étude de l\'utilisabilité"</string> - <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Durée de vibration à chaque pression"</string> - <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Volume sonore à chaque pression"</string> + <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Paramètres de durée du vibreur à chaque pression de touche"</string> + <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Paramètres de volume sonore à chaque pression de touche"</string> </resources> diff --git a/java/res/values-lt/donottranslate-more-keys.xml b/java/res/values-lt/donottranslate-more-keys.xml index 6b81e4509..e36ce6a66 100644 --- a/java/res/values-lt/donottranslate-more-keys.xml +++ b/java/res/values-lt/donottranslate-more-keys.xml @@ -18,11 +18,20 @@ */ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="more_keys_for_a">ą,à,á,â,ä,æ,ã,å,ā</string> - <string name="more_keys_for_e">3,ė,ę,è,é,ê,ë,ē</string> - <string name="more_keys_for_i">8,į,î,ï,ì,í,ī</string> - <string name="more_keys_for_u">7,ų,ū,û,ü,ù,ú</string> - <string name="more_keys_for_s">š,ß,ś</string> + <string name="more_keys_for_a">ą,ä,ā,à,á,â,ã,å,æ</string> + <string name="more_keys_for_e">3,ė,ę,ē,è,é,ê,ë,ě</string> + <string name="more_keys_for_i">8,į,ī,ì,í,î,ï,ı</string> + <string name="more_keys_for_o">9,ö,õ,ò,ó,ô,œ,ő,ø</string> + <string name="more_keys_for_u">7,ū,ų,ü,ū,ù,ú,û,ů,ű</string> + <string name="more_keys_for_s">š,ß,ś,ş</string> + <string name="more_keys_for_n">ņ,ñ,ń,ń</string> <string name="more_keys_for_c">č,ç,ć</string> - <string name="more_keys_for_z">ž,ź,ż</string> + <string name="more_keys_for_y">6,ý,ÿ</string> + <string name="more_keys_for_d">ď</string> + <string name="more_keys_for_r">4,ŗ,ř,ŕ</string> + <string name="more_keys_for_t">5,ţ,ť</string> + <string name="more_keys_for_z">ž,ż,ź</string> + <string name="more_keys_for_k">ķ</string> + <string name="more_keys_for_l">ļ,ł,ĺ,ľ</string> + <string name="more_keys_for_g">ģ,ğ</string> </resources> diff --git a/java/res/values-lv/donottranslate-more-keys.xml b/java/res/values-lv/donottranslate-more-keys.xml index 77e1c26a0..8514e738d 100644 --- a/java/res/values-lv/donottranslate-more-keys.xml +++ b/java/res/values-lv/donottranslate-more-keys.xml @@ -18,16 +18,20 @@ */ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="more_keys_for_a">ā,à,á,â,ä,æ,ã,å</string> - <string name="more_keys_for_e">3,ē,è,é,ê,ë,ę,ė</string> - <string name="more_keys_for_i">8,ī,î,ï,ì,í,į</string> - <string name="more_keys_for_u">7,ū,û,ü,ù,ú</string> - <string name="more_keys_for_s">š,ß,ś</string> - <string name="more_keys_for_n">ņ,ñ,ń</string> + <string name="more_keys_for_a">ā,à,á,â,ã,ä,å,æ,ą</string> + <string name="more_keys_for_e">3,ē,ė,è,é,ê,ë,ę,ě</string> + <string name="more_keys_for_i">8,ī,į,ì,í,î,ï,ı</string> + <string name="more_keys_for_o">9,ò,ó,ô,õ,ö,œ,ő,ø</string> + <string name="more_keys_for_u">7,ū,ų,ù,ú,û,ü,ů,ű</string> + <string name="more_keys_for_s">š,ß,ś,ş</string> + <string name="more_keys_for_n">ņ,ñ,ń,ń</string> <string name="more_keys_for_c">č,ç,ć</string> - <string name="more_keys_for_r">4,ŗ</string> - <string name="more_keys_for_z">ž,ź,ż</string> + <string name="more_keys_for_y">6,ý,ÿ</string> + <string name="more_keys_for_d">ď</string> + <string name="more_keys_for_r">4,ŗ,ř,ŕ</string> + <string name="more_keys_for_t">5,ţ,ť</string> + <string name="more_keys_for_z">ž,ż,ź</string> <string name="more_keys_for_k">ķ</string> - <string name="more_keys_for_l">ļ,ł</string> - <string name="more_keys_for_g">ģ</string> + <string name="more_keys_for_l">ļ,ł,ĺ,ľ</string> + <string name="more_keys_for_g">ģ,ğ</string> </resources> diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index 0c9ca4f4a..15e006593 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -185,6 +185,8 @@ <declare-styleable name="Keyboard_Key"> <!-- The unicode value that this key outputs. --> <attr name="code" format="integer" /> + <!-- The alternate unicode value that this key outputs while typing. --> + <attr name="altCode" format="integer" /> <!-- The keys to display in the more keys keyboard. --> <attr name="moreKeys" format="string" /> <!-- Maximum column of more keys keyboard --> @@ -196,17 +198,22 @@ <enum name="action" value="2" /> <enum name="sticky" value="3" /> </attr> - <!-- Whether long-pressing on this key will make it repeat. --> - <attr name="isRepeatable" format="boolean" /> + <!-- The key action flags. --> + <attr name="keyActionFlags" format="integer"> + <!-- This should be aligned with Key.ACTION_FLAGS_* --> + <flag name="isRepeatable" value="0x01" /> + <flag name="noKeyPreview" value="0x02" /> + <flag name="altCodeWhileTyping" value="0x04" /> + </attr> <!-- The string of characters to output when this key is pressed. --> <attr name="keyOutputText" format="string" /> <!-- The label to display on the key. --> <attr name="keyLabel" format="string" /> <!-- The hint label to display on the key in conjunction with the label. --> <attr name="keyHintLabel" format="string" /> - <!-- The key label option. --> - <attr name="keyLabelOption" format="integer"> - <!-- This should be aligned with Key.LABEL_OPTION_* --> + <!-- The key label flags. --> + <attr name="keyLabelFlags" format="integer"> + <!-- This should be aligned with Key.LABEL_FLAGS__* --> <flag name="alignLeft" value="0x01" /> <flag name="alignRight" value="0x02" /> <flag name="alignLeftOfCenter" value="0x08" /> @@ -247,8 +254,6 @@ </attr> <!-- The key style to specify a set of key attributes defined by <key_style/> --> <attr name="keyStyle" format="string" /> - <!-- The key is enabled and responds on press. --> - <attr name="enabled" format="boolean" /> <!-- Visual insets --> <attr name="visualInsetsLeft" format="dimension|fraction" /> <attr name="visualInsetsRight" format="dimension|fraction" /> diff --git a/java/res/values/config.xml b/java/res/values/config.xml index 3f676ab25..bad4bc625 100644 --- a/java/res/values/config.xml +++ b/java/res/values/config.xml @@ -81,8 +81,8 @@ will be subject to auto-correction. --> <item>0</item> </string-array> - <!-- Threshold of the normalized score of the best suggestion for the spell checker to declare a word to be "likely" --> - <string name="spellchecker_likely_threshold_value" translatable="false">0.11</string> + <!-- Threshold of the normalized score of the best suggestion for the spell checker to declare a word to be "recommended" --> + <string name="spellchecker_recommended_threshold_value" translatable="false">0.11</string> <!-- Threshold of the normalized score of any dictionary lookup to be offered as a suggestion by the spell checker --> <string name="spellchecker_suggestion_threshold_value" translatable="false">0.03</string> <!-- Screen metrics for logging. diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index e00547a62..8f999215e 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -31,11 +31,11 @@ <!-- Title for the spell checking service settings screen --> <string name="android_spell_checker_settings">Spell checking settings</string> - <!-- Title for the "use proximity" option for spell checking [CHAR LIMIT=25] --> - <string name="use_proximity_option_title">Use proximity data</string> + <!-- Title for the spell checker option to turn on/off contact names lookup [CHAR LIMIT=25] --> + <string name="use_contacts_for_spellchecking_option_title">Look up contact names</string> - <!-- Description for the "use proximity" option for spell checking [CHAR LIMIT=65] --> - <string name="use_proximity_option_summary">Use a keyboard-like proximity algorithm for spell checking</string> + <!-- Description for the spell checker option to turn on/off contact names lookup. [CHAR LIMIT=65] --> + <string name="use_contacts_for_spellchecking_option_summary">Spell checker uses entries from your contact list</string> <!-- Option to provide vibrate/haptic feedback on keypress --> <string name="vibrate_on_keypress">Vibrate on keypress</string> diff --git a/java/res/xml-sw600dp-land/kbd_number.xml b/java/res/xml-sw600dp-land/kbd_number.xml new file mode 100644 index 000000000..7e3188b0f --- /dev/null +++ b/java/res/xml-sw600dp-land/kbd_number.xml @@ -0,0 +1,28 @@ +<?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. +*/ +--> + +<Keyboard + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardHorizontalEdgesPadding="10%p" + latin:keyWidth="15.00%p" +> + <include + latin:keyboardLayout="@xml/kbd_rows_number" /> +</Keyboard> diff --git a/java/res/xml-sw600dp-land/kbd_phone.xml b/java/res/xml-sw600dp-land/kbd_phone.xml new file mode 100644 index 000000000..28df7efa3 --- /dev/null +++ b/java/res/xml-sw600dp-land/kbd_phone.xml @@ -0,0 +1,28 @@ +<?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. +*/ +--> + +<Keyboard + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardHorizontalEdgesPadding="10%p" + latin:keyWidth="15.00%p" +> + <include + latin:keyboardLayout="@xml/kbd_rows_phone" /> +</Keyboard> diff --git a/java/res/xml-sw600dp-land/kbd_phone_shift.xml b/java/res/xml-sw600dp-land/kbd_phone_shift.xml new file mode 100644 index 000000000..daf1d18c5 --- /dev/null +++ b/java/res/xml-sw600dp-land/kbd_phone_shift.xml @@ -0,0 +1,28 @@ +<?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. +*/ +--> + +<Keyboard + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardHorizontalEdgesPadding="10%p" + latin:keyWidth="15.00%p" +> + <include + latin:keyboardLayout="@xml/kbd_rows_phone_shift" /> +</Keyboard> diff --git a/java/res/xml-sw600dp/kbd_key_styles.xml b/java/res/xml-sw600dp/kbd_key_styles.xml index 25fa8b265..aba1a8029 100644 --- a/java/res/xml-sw600dp/kbd_key_styles.xml +++ b/java/res/xml-sw600dp/kbd_key_styles.xml @@ -33,7 +33,7 @@ <default> <key-style latin:styleName="f2PopupStyle" - latin:keyLabelOption="hasPopupHint" + latin:keyLabelFlags="hasPopupHint" latin:moreKeys="\@icon/3|\@integer/key_settings" latin:backgroundType="functional" /> </default> @@ -44,40 +44,48 @@ latin:code="@integer/key_shift" latin:keyIcon="iconShiftKey" latin:keyIconShifted="iconShiftedShiftKey" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="sticky" /> <key-style latin:styleName="deleteKeyStyle" latin:code="@integer/key_delete" latin:keyIcon="iconDeleteKey" - latin:backgroundType="functional" - latin:isRepeatable="true" /> + latin:keyActionFlags="isRepeatable|noKeyPreview" + latin:backgroundType="functional" /> <key-style latin:styleName="returnKeyStyle" latin:code="@integer/key_return" latin:keyIcon="iconReturnKey" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <key-style latin:styleName="spaceKeyStyle" - latin:code="@integer/key_space" /> + latin:code="@integer/key_space" + latin:keyActionFlags="noKeyPreview" /> <key-style latin:styleName="nonSpecialBackgroundSpaceKeyStyle" - latin:code="@integer/key_space" /> + latin:code="@integer/key_space" + latin:keyActionFlags="noKeyPreview" /> <key-style latin:styleName="smileyKeyStyle" latin:keyLabel=":-)" latin:keyOutputText=":-) " - latin:keyLabelOption="hasPopupHint" + latin:keyLabelFlags="hasPopupHint" latin:moreKeys="@string/more_keys_for_smiley" latin:maxMoreKeysColumn="5" /> <key-style latin:styleName="shortcutKeyStyle" latin:code="@integer/key_shortcut" latin:keyIcon="iconShortcutKey" + latin:keyActionFlags="noKeyPreview|altCodeWhileTyping" + latin:altCode="@integer/key_space" latin:parentStyle="f2PopupStyle" /> <key-style latin:styleName="settingsKeyStyle" latin:code="@integer/key_settings" latin:keyIcon="iconSettingsKey" + latin:keyActionFlags="noKeyPreview|altCodeWhileTyping" + latin:altCode="@integer/key_space" latin:backgroundType="functional" /> <key-style latin:styleName="tabKeyStyle" @@ -89,26 +97,30 @@ latin:styleName="toSymbolKeyStyle" latin:code="@integer/key_switch_alpha_symbol" latin:keyLabel="@string/label_to_symbol_key" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <key-style latin:styleName="toAlphaKeyStyle" latin:code="@integer/key_switch_alpha_symbol" latin:keyLabel="@string/label_to_alpha_key" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <key-style latin:styleName="toMoreSymbolKeyStyle" latin:code="@integer/key_shift" latin:keyLabel="@string/label_to_more_symbol_for_tablet_key" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <key-style latin:styleName="backFromMoreSymbolKeyStyle" latin:code="@integer/key_shift" latin:keyLabel="@string/label_to_symbol_key" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <key-style latin:styleName="comKeyStyle" latin:keyLabel="@string/keylabel_for_popular_domain" - latin:keyLabelOption="fontNormal|hasPopupHint" + latin:keyLabelFlags="fontNormal|hasPopupHint" latin:keyOutputText="@string/keylabel_for_popular_domain" latin:moreKeys="@string/more_keys_for_popular_domain" /> </merge> diff --git a/java/res/xml-sw600dp/kbd_number.xml b/java/res/xml-sw600dp/kbd_number.xml index 46114dedf..ad588d7ed 100644 --- a/java/res/xml-sw600dp/kbd_number.xml +++ b/java/res/xml-sw600dp/kbd_number.xml @@ -20,190 +20,8 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyWidth="16.75%p" + latin:keyWidth="15.00%p" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> - <include - latin:keyboardLayout="@xml/kbd_numkey_styles" /> - <switch> - <case - latin:passwordInput="true" - > - <Row> - <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> - <Spacer - latin:keyWidth="24.875%p" /> - <Key - latin:keyStyle="num1KeyStyle" /> - <Key - latin:keyStyle="num2KeyStyle" /> - <Key - latin:keyStyle="num3KeyStyle" /> - <Key - latin:keyStyle="deleteKeyStyle" - latin:keyXPos="-11.00%p" - latin:keyWidth="fillRight" /> - </Row> - <Row> - <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> - <Spacer - latin:keyWidth="24.875%p" /> - <Key - latin:keyStyle="num4KeyStyle" /> - <Key - latin:keyStyle="num5KeyStyle" /> - <Key - latin:keyStyle="num6KeyStyle" /> - <Key - latin:keyStyle="returnKeyStyle" - latin:keyXPos="-11.00%p" - latin:keyWidth="fillRight" /> - </Row> - <Row> - <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> - <Spacer - latin:keyWidth="24.875%p" /> - <Key - latin:keyStyle="num7KeyStyle" /> - <Key - latin:keyStyle="num8KeyStyle" /> - <Key - latin:keyStyle="num9KeyStyle" /> - <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> - <Spacer - latin:keyWidth="0%p" /> - </Row> - <Row> - <Key - latin:keyStyle="tabKeyStyle" - latin:keyWidth="11.00%p" /> - <Spacer - latin:keyXPos="24.875%p" /> - <Key - latin:keyStyle="num0KeyStyle" /> - <Spacer - latin:keyXPos="-11.00%p" - latin:keyWidth="0%p" /> - <include - latin:keyboardLayout="@xml/kbd_qwerty_f2" /> - </Row> - </case> - <!-- latin:passwordInput="false" --> - <default> - <Row> - <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> - <Spacer - latin:keyWidth="11.00%p" /> - <Key - latin:keyLabel="-" - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:keyLabel="+" - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:keyLabel="." - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:keyLabel="1" - latin:keyStyle="numKeyStyle" - latin:keyXPos="38.75%p" /> - <Key - latin:keyLabel="2" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyLabel="3" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyStyle="deleteKeyStyle" - latin:keyXPos="-11.00%p" - latin:keyWidth="fillBoth" /> - </Row> - <Row> - <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> - <Spacer - latin:keyWidth="11.00%p" /> - <Key - latin:keyStyle="numStarKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:keyLabel="/" - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:keyLabel="," - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:keyLabel="4" - latin:keyStyle="numKeyStyle" - latin:keyXPos="38.75%p" /> - <Key - latin:keyLabel="5" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyLabel="6" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyStyle="returnKeyStyle" - latin:keyXPos="-11.00%p" - latin:keyWidth="fillBoth" /> - </Row> - <Row> - <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> - <Spacer - latin:keyWidth="11.00%p" /> - <Key - latin:keyLabel="(" - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:keyLabel=")" - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:keyLabel="=" - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:keyLabel="7" - latin:keyStyle="numKeyStyle" - latin:keyXPos="38.75%p" /> - <Key - latin:keyLabel="8" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyLabel="9" - latin:keyStyle="numKeyStyle" /> - <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> - <Spacer - latin:keyWidth="0%p" /> - </Row> - <Row> - <Key - latin:keyStyle="tabKeyStyle" - latin:keyWidth="11.00%p" /> - <Key - latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle" - latin:keyWidth="27.75%p" /> - <Key - latin:keyStyle="numStarKeyStyle" - latin:keyXPos="38.75%p" /> - <Key - latin:keyLabel="0" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyLabel="#" - latin:keyStyle="numKeyStyle" /> - <Spacer - latin:keyXPos="-11.00%p" - latin:keyWidth="0%p" /> - <include - latin:keyboardLayout="@xml/kbd_qwerty_f2" /> - </Row> - </default> - </switch> + latin:keyboardLayout="@xml/kbd_rows_number" /> </Keyboard> diff --git a/java/res/xml-sw600dp/kbd_phone.xml b/java/res/xml-sw600dp/kbd_phone.xml index 303f8145b..ce769b8f7 100644 --- a/java/res/xml-sw600dp/kbd_phone.xml +++ b/java/res/xml-sw600dp/kbd_phone.xml @@ -20,104 +20,8 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyWidth="16.75%p" + latin:keyWidth="15.00%p" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> - <include - latin:keyboardLayout="@xml/kbd_numkey_styles" /> - <Row> - <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> - <Spacer - latin:keyWidth="15.625%p" /> - <Key - latin:keyLabel="-" - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:keyLabel="+" - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:keyStyle="num1KeyStyle" - latin:keyXPos="38.867%p" /> - <Key - latin:keyStyle="num2KeyStyle" /> - <Key - latin:keyStyle="num3KeyStyle" /> - <Key - latin:keyStyle="deleteKeyStyle" - latin:keyXPos="-11.00%p" - latin:keyWidth="fillBoth" /> - </Row> - <Row> - <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> - <Spacer - latin:keyWidth="15.625%p" /> - <Key - latin:keyLabel="," - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:keyLabel="." - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:keyStyle="num4KeyStyle" - latin:keyXPos="38.867%p" /> - <Key - latin:keyStyle="num5KeyStyle" /> - <Key - latin:keyStyle="num6KeyStyle" /> - <Key - latin:keyStyle="returnKeyStyle" - latin:keyXPos="-11.00%p" - latin:keyWidth="fillBoth" /> - </Row> - <Row> - <Key - latin:keyStyle="toMoreSymbolKeyStyle" - latin:keyWidth="11.0%p" /> - <Key - latin:keyLabel="(" - latin:keyStyle="numKeyStyle" - latin:keyXPos="15.625%p" - latin:keyWidth="9.25%p" /> - <Key - latin:keyLabel=")" - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:keyStyle="num7KeyStyle" - latin:keyXPos="38.867%p" /> - <Key - latin:keyStyle="num8KeyStyle" /> - <Key - latin:keyStyle="num9KeyStyle" /> - <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> - <Spacer - latin:keyWidth="0%p" /> - </Row> - <Row> - <Key - latin:keyStyle="tabKeyStyle" - latin:keyWidth="11.00%p" /> - <Key - latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle" - latin:keyXPos="15.625%p" - latin:keyWidth="18.50%p" /> - <Key - latin:keyStyle="numStarKeyStyle" - latin:keyXPos="38.867%p" /> - <Key - latin:keyStyle="num0KeyStyle" /> - <Key - latin:keyLabel="#" - latin:keyStyle="numKeyStyle" /> - <Spacer - latin:keyXPos="-11.00%p" - latin:keyWidth="0%p" /> - <include - latin:keyboardLayout="@xml/kbd_qwerty_f2" /> - </Row> + latin:keyboardLayout="@xml/kbd_rows_phone" /> </Keyboard> diff --git a/java/res/xml-sw600dp/kbd_phone_shift.xml b/java/res/xml-sw600dp/kbd_phone_shift.xml index 4c4f8ad12..3753deb8c 100644 --- a/java/res/xml-sw600dp/kbd_phone_shift.xml +++ b/java/res/xml-sw600dp/kbd_phone_shift.xml @@ -20,116 +20,8 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyWidth="16.75%p" + latin:keyWidth="15.00%p" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> - <include - latin:keyboardLayout="@xml/kbd_numkey_styles" /> - <Row> - <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> - <Spacer - latin:keyWidth="11.00%p" /> - <Key - latin:keyLabel="-" - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:keyLabel="+" - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:code="44" - latin:keyLabel="@string/label_pause_key" - latin:keyLabelOption="followKeyHintLabelRatio|autoXScale" - latin:keyWidth="9.25%p" /> - <Key - latin:keyStyle="num1KeyStyle" - latin:keyXPos="38.867%p" /> - <Key - latin:keyStyle="num2KeyStyle" /> - <Key - latin:keyStyle="num3KeyStyle" /> - <Key - latin:keyStyle="deleteKeyStyle" - latin:keyXPos="-11.00%p" - latin:keyWidth="fillBoth" /> - </Row> - <Row> - <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> - <Spacer - latin:keyWidth="11.00%p" /> - <Key - latin:keyLabel="," - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:keyLabel="." - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:code="59" - latin:keyLabel="@string/label_wait_key" - latin:keyLabelOption="followKeyHintLabelRatio|autoXScale" - latin:keyWidth="9.25%p" /> - <Key - latin:keyStyle="num4KeyStyle" - latin:keyXPos="38.867%p" /> - <Key - latin:keyStyle="num5KeyStyle" /> - <Key - latin:keyStyle="num6KeyStyle" /> - <Key - latin:keyStyle="returnKeyStyle" - latin:keyXPos="-11.00%p" - latin:keyWidth="fillBoth" /> - </Row> - <Row> - <Key - latin:keyStyle="backFromMoreSymbolKeyStyle" - latin:keyWidth="11.00%p" /> - <Key - latin:keyLabel="(" - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:keyLabel=")" - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:keyLabel="N" - latin:keyStyle="numKeyStyle" - latin:keyWidth="9.25%p" /> - <Key - latin:keyStyle="num7KeyStyle" - latin:keyXPos="38.867%p" /> - <Key - latin:keyStyle="num8KeyStyle" /> - <Key - latin:keyStyle="num9KeyStyle" /> - <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> - <Spacer - latin:keyWidth="0%p" /> - </Row> - <Row> - <Key - latin:keyStyle="tabKeyStyle" - latin:keyWidth="11.00%p" /> - <Key - latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle" - latin:keyWidth="27.75%p" /> - <Key - latin:keyStyle="numStarKeyStyle" - latin:keyXPos="38.867%p" /> - <Key - latin:keyStyle="num0KeyStyle" /> - <Key - latin:keyLabel="#" - latin:keyStyle="numKeyStyle" /> - <Spacer - latin:keyXPos="-11.00%p" - latin:keyWidth="0%p" /> - <include - latin:keyboardLayout="@xml/kbd_qwerty_f2" /> - </Row> + latin:keyboardLayout="@xml/kbd_rows_phone_shift" /> </Keyboard> diff --git a/java/res/xml-sw600dp/kbd_qwerty_row4.xml b/java/res/xml-sw600dp/kbd_qwerty_row4.xml index ef0292279..54ca22b67 100644 --- a/java/res/xml-sw600dp/kbd_qwerty_row4.xml +++ b/java/res/xml-sw600dp/kbd_qwerty_row4.xml @@ -45,7 +45,7 @@ <default> <Key latin:keyLabel="/" - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="\@" latin:moreKeys="\@" /> </default> diff --git a/java/res/xml-sw600dp/kbd_row3_comma_period.xml b/java/res/xml-sw600dp/kbd_row3_comma_period.xml index b84443078..6a95ca1a3 100644 --- a/java/res/xml-sw600dp/kbd_row3_comma_period.xml +++ b/java/res/xml-sw600dp/kbd_row3_comma_period.xml @@ -33,12 +33,12 @@ <default> <Key latin:keyLabel="," - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="!" latin:moreKeys="!" /> <Key latin:keyLabel="." - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="\?" latin:moreKeys="\?" /> </default> diff --git a/java/res/xml-sw600dp/kbd_row3_smiley.xml b/java/res/xml-sw600dp/kbd_row3_smiley.xml index f9b647cdf..c94ec0cee 100644 --- a/java/res/xml-sw600dp/kbd_row3_smiley.xml +++ b/java/res/xml-sw600dp/kbd_row3_smiley.xml @@ -35,7 +35,7 @@ > <Key latin:keyLabel="-" - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="_" latin:moreKeys="_" latin:keyXPos="-8.9%p" @@ -46,7 +46,7 @@ > <Key latin:keyLabel=":" - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="+" latin:moreKeys="+" latin:keyXPos="-8.9%p" diff --git a/java/res/xml-sw600dp/kbd_row4_apostrophe_dash.xml b/java/res/xml-sw600dp/kbd_row4_apostrophe_dash.xml index 9536e81da..4eb82d24a 100644 --- a/java/res/xml-sw600dp/kbd_row4_apostrophe_dash.xml +++ b/java/res/xml-sw600dp/kbd_row4_apostrophe_dash.xml @@ -33,14 +33,14 @@ > <Key latin:keyLabel="/" - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel=":" latin:moreKeys=":" /> </case> <default> <Key latin:keyLabel="@string/keylabel_for_apostrophe" - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="@string/keyhintlabel_for_apostrophe" latin:moreKeys="@string/more_keys_for_apostrophe" /> </default> @@ -55,7 +55,7 @@ <default> <Key latin:keyLabel="@string/keylabel_for_dash" - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="@string/keyhintlabel_for_dash" latin:moreKeys="@string/more_keys_for_dash" /> </default> diff --git a/java/res/xml-sw600dp/kbd_rows_arabic.xml b/java/res/xml-sw600dp/kbd_rows_arabic.xml index c2d3cd4cc..55c02f211 100644 --- a/java/res/xml-sw600dp/kbd_rows_arabic.xml +++ b/java/res/xml-sw600dp/kbd_rows_arabic.xml @@ -158,7 +158,7 @@ > <Key latin:keyLabel="-" - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="_" latin:moreKeys="_" /> </case> @@ -167,7 +167,7 @@ > <Key latin:keyLabel=":" - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="+" latin:moreKeys="+" /> </case> diff --git a/java/res/xml-sw600dp/kbd_rows_azerty.xml b/java/res/xml-sw600dp/kbd_rows_azerty.xml index 8ae74557c..46967899b 100644 --- a/java/res/xml-sw600dp/kbd_rows_azerty.xml +++ b/java/res/xml-sw600dp/kbd_rows_azerty.xml @@ -132,12 +132,12 @@ <default> <Key latin:keyLabel="," - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="!" latin:moreKeys="!" /> <Key latin:keyLabel="." - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="\?" latin:moreKeys="\?" /> </default> diff --git a/java/res/xml-sw600dp/kbd_rows_hebrew.xml b/java/res/xml-sw600dp/kbd_rows_hebrew.xml index a8adbd34c..4166745b7 100644 --- a/java/res/xml-sw600dp/kbd_rows_hebrew.xml +++ b/java/res/xml-sw600dp/kbd_rows_hebrew.xml @@ -94,7 +94,7 @@ > <Key latin:keyLabel="-" - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="_" latin:moreKeys="_" latin:keyWidth="10.0%p" /> @@ -104,7 +104,7 @@ > <Key latin:keyLabel=":" - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="+" latin:moreKeys="+" latin:keyWidth="10.0%p" /> diff --git a/java/res/xml-sw600dp/kbd_rows_number.xml b/java/res/xml-sw600dp/kbd_rows_number.xml new file mode 100644 index 000000000..cfb24212b --- /dev/null +++ b/java/res/xml-sw600dp/kbd_rows_number.xml @@ -0,0 +1,208 @@ +<?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. +*/ +--> + +<merge + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" +> + <include + latin:keyboardLayout="@xml/kbd_key_styles" /> + <include + latin:keyboardLayout="@xml/kbd_numkey_styles" /> + <switch> + <case + latin:passwordInput="true" + > + <Row> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="27.50%p" /> + <Key + latin:keyStyle="num1KeyStyle" /> + <Key + latin:keyStyle="num2KeyStyle" /> + <Key + latin:keyStyle="num3KeyStyle" /> + <Key + latin:keyStyle="deleteKeyStyle" + latin:keyXPos="-11.00%p" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="27.50%p" /> + <Key + latin:keyStyle="num4KeyStyle" /> + <Key + latin:keyStyle="num5KeyStyle" /> + <Key + latin:keyStyle="num6KeyStyle" /> + <Key + latin:keyStyle="returnKeyStyle" + latin:keyXPos="-11.00%p" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="27.50%p" /> + <Key + latin:keyStyle="num7KeyStyle" /> + <Key + latin:keyStyle="num8KeyStyle" /> + <Key + latin:keyStyle="num9KeyStyle" /> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="0%p" /> + </Row> + <Row> + <Key + latin:keyStyle="tabKeyStyle" + latin:keyWidth="11.00%p" /> + <Key + latin:keyStyle="num0KeyStyle" + latin:keyXPos="42.50%p"/> + <Spacer + latin:keyXPos="-11.00%p" + latin:keyWidth="0%p" /> + <include + latin:keyboardLayout="@xml/kbd_qwerty_f2" /> + </Row> + </case> + <!-- latin:passwordInput="false" --> + <default> + <Row> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="12.75%p" /> + <Key + latin:keyLabel="-" + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyLabel="+" + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyLabel="." + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyLabel="1" + latin:keyStyle="numKeyStyle" + latin:keyXPos="42.25%p" /> + <Key + latin:keyLabel="2" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyLabel="3" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyStyle="deleteKeyStyle" + latin:keyXPos="-11.00%p" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="12.75%p" /> + <Key + latin:keyStyle="numStarKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyLabel="/" + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyLabel="," + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyLabel="4" + latin:keyStyle="numKeyStyle" + latin:keyXPos="42.25%p" /> + <Key + latin:keyLabel="5" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyLabel="6" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyStyle="returnKeyStyle" + latin:keyXPos="-11.00%p" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="12.75%p" /> + <Key + latin:keyLabel="(" + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyLabel=")" + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyLabel="=" + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyLabel="7" + latin:keyStyle="numKeyStyle" + latin:keyXPos="42.25%p" /> + <Key + latin:keyLabel="8" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyLabel="9" + latin:keyStyle="numKeyStyle" /> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="0%p" /> + </Row> + <Row> + <Key + latin:keyStyle="numTabKeyStyle" + latin:keyWidth="11.00%p" /> + <Key + latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle" + latin:keyWidth="27.75%p" + latin:keyXPos="12.75%p" /> + <Key + latin:keyStyle="numStarKeyStyle" + latin:keyXPos="42.25%p" /> + <Key + latin:keyLabel="0" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyLabel="#" + latin:keyStyle="numKeyStyle" /> + <Spacer + latin:keyXPos="-11.00%p" + latin:keyWidth="0%p" /> + <include + latin:keyboardLayout="@xml/kbd_qwerty_f2" /> + </Row> + </default> + </switch> +</merge> diff --git a/java/res/xml-sw600dp/kbd_rows_phone.xml b/java/res/xml-sw600dp/kbd_rows_phone.xml new file mode 100644 index 000000000..69d058fd8 --- /dev/null +++ b/java/res/xml-sw600dp/kbd_rows_phone.xml @@ -0,0 +1,122 @@ +<?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. +*/ +--> + +<merge + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" +> + <include + latin:keyboardLayout="@xml/kbd_key_styles" /> + <include + latin:keyboardLayout="@xml/kbd_numkey_styles" /> + <Row> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="17.375%p" /> + <Key + latin:keyLabel="-" + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyLabel="+" + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyStyle="num1KeyStyle" + latin:keyXPos="42.25%p" /> + <Key + latin:keyStyle="num2KeyStyle" /> + <Key + latin:keyStyle="num3KeyStyle" /> + <Key + latin:keyStyle="deleteKeyStyle" + latin:keyXPos="-11.00%p" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="17.375%p" /> + <Key + latin:keyLabel="," + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyLabel="." + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyStyle="num4KeyStyle" + latin:keyXPos="42.25%p" /> + <Key + latin:keyStyle="num5KeyStyle" /> + <Key + latin:keyStyle="num6KeyStyle" /> + <Key + latin:keyStyle="returnKeyStyle" + latin:keyXPos="-11.00%p" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <Key + latin:keyStyle="toMoreSymbolKeyStyle" + latin:keyWidth="11.0%p" /> + <Key + latin:keyLabel="(" + latin:keyStyle="numKeyStyle" + latin:keyXPos="17.375%p" + latin:keyWidth="9.25%p" /> + <Key + latin:keyLabel=")" + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyStyle="num7KeyStyle" + latin:keyXPos="42.25%p" /> + <Key + latin:keyStyle="num8KeyStyle" /> + <Key + latin:keyStyle="num9KeyStyle" /> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="0%p" /> + </Row> + <Row> + <Key + latin:keyStyle="numTabKeyStyle" + latin:keyWidth="11.00%p" /> + <Key + latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle" + latin:keyWidth="18.50%p" + latin:keyXPos="17.375%p" /> + <Key + latin:keyStyle="numStarKeyStyle" + latin:keyXPos="42.25%p" /> + <Key + latin:keyStyle="num0KeyStyle" /> + <Key + latin:keyLabel="#" + latin:keyStyle="numKeyStyle" /> + <Spacer + latin:keyXPos="-11.00%p" + latin:keyWidth="0%p" /> + <include + latin:keyboardLayout="@xml/kbd_qwerty_f2" /> + </Row> +</merge> diff --git a/java/res/xml-sw600dp/kbd_rows_phone_shift.xml b/java/res/xml-sw600dp/kbd_rows_phone_shift.xml new file mode 100644 index 000000000..04db6780f --- /dev/null +++ b/java/res/xml-sw600dp/kbd_rows_phone_shift.xml @@ -0,0 +1,132 @@ +<?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. +*/ +--> + +<merge + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" +> + <include + latin:keyboardLayout="@xml/kbd_key_styles" /> + <include + latin:keyboardLayout="@xml/kbd_numkey_styles" /> + <Row> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="12.75%p" /> + <Key + latin:keyLabel="-" + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyLabel="+" + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyStyle="numPauseKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyStyle="num1KeyStyle" + latin:keyXPos="42.25%p" /> + <Key + latin:keyStyle="num2KeyStyle" /> + <Key + latin:keyStyle="num3KeyStyle" /> + <Key + latin:keyStyle="deleteKeyStyle" + latin:keyXPos="-11.00%p" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="12.75%p" /> + <Key + latin:keyLabel="," + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyLabel="." + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyStyle="numWaitKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyStyle="num4KeyStyle" + latin:keyXPos="42.25%p" /> + <Key + latin:keyStyle="num5KeyStyle" /> + <Key + latin:keyStyle="num6KeyStyle" /> + <Key + latin:keyStyle="returnKeyStyle" + latin:keyXPos="-11.00%p" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <Key + latin:keyStyle="backFromMoreSymbolKeyStyle" + latin:keyWidth="11.00%p" /> + <Key + latin:keyLabel="(" + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" + latin:keyXPos="12.75%p" /> + <Key + latin:keyLabel=")" + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyLabel="N" + latin:keyStyle="numKeyStyle" + latin:keyWidth="9.25%p" /> + <Key + latin:keyStyle="num7KeyStyle" + latin:keyXPos="42.25%p" /> + <Key + latin:keyStyle="num8KeyStyle" /> + <Key + latin:keyStyle="num9KeyStyle" /> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="0%p" /> + </Row> + <Row> + <Key + latin:keyStyle="numTabKeyStyle" + latin:keyWidth="11.00%p" /> + <Key + latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle" + latin:keyWidth="27.75%p" + latin:keyXPos="12.75%p" /> + <Key + latin:keyStyle="numStarKeyStyle" + latin:keyXPos="42.25%p" /> + <Key + latin:keyStyle="num0KeyStyle" /> + <Key + latin:keyLabel="#" + latin:keyStyle="numKeyStyle" /> + <Spacer + latin:keyXPos="-11.00%p" + latin:keyWidth="0%p" /> + <include + latin:keyboardLayout="@xml/kbd_qwerty_f2" /> + </Row> +</merge> diff --git a/java/res/xml-sw600dp/kbd_rows_qwertz.xml b/java/res/xml-sw600dp/kbd_rows_qwertz.xml index 98667e09c..d7d13d5d1 100644 --- a/java/res/xml-sw600dp/kbd_rows_qwertz.xml +++ b/java/res/xml-sw600dp/kbd_rows_qwertz.xml @@ -99,12 +99,12 @@ <default> <Key latin:keyLabel="," - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="!" latin:moreKeys="!" /> <Key latin:keyLabel="." - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="\?" latin:moreKeys="\?" /> </default> diff --git a/java/res/xml-sw600dp/kbd_rows_russian.xml b/java/res/xml-sw600dp/kbd_rows_russian.xml index cc9ad3aa7..3395065ed 100644 --- a/java/res/xml-sw600dp/kbd_rows_russian.xml +++ b/java/res/xml-sw600dp/kbd_rows_russian.xml @@ -122,12 +122,12 @@ <default> <Key latin:keyLabel="," - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="!" latin:moreKeys="!" /> <Key latin:keyLabel="." - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="\?" latin:moreKeys="\?" /> </default> diff --git a/java/res/xml-sw768dp-land/kbd_number.xml b/java/res/xml-sw768dp-land/kbd_number.xml new file mode 100644 index 000000000..3106dc34e --- /dev/null +++ b/java/res/xml-sw768dp-land/kbd_number.xml @@ -0,0 +1,28 @@ +<?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. +*/ +--> + +<Keyboard + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardHorizontalEdgesPadding="10%p" + latin:keyWidth="13.250%p" +> + <include + latin:keyboardLayout="@xml/kbd_rows_number" /> +</Keyboard> diff --git a/java/res/xml-sw768dp-land/kbd_phone.xml b/java/res/xml-sw768dp-land/kbd_phone.xml new file mode 100644 index 000000000..7c7af5739 --- /dev/null +++ b/java/res/xml-sw768dp-land/kbd_phone.xml @@ -0,0 +1,28 @@ +<?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. +*/ +--> + +<Keyboard + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardHorizontalEdgesPadding="10%p" + latin:keyWidth="13.250%p" +> + <include + latin:keyboardLayout="@xml/kbd_rows_phone" /> +</Keyboard> diff --git a/java/res/xml-sw768dp-land/kbd_phone_shift.xml b/java/res/xml-sw768dp-land/kbd_phone_shift.xml new file mode 100644 index 000000000..04b018cfe --- /dev/null +++ b/java/res/xml-sw768dp-land/kbd_phone_shift.xml @@ -0,0 +1,28 @@ +<?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. +*/ +--> + +<Keyboard + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardHorizontalEdgesPadding="10%p" + latin:keyWidth="13.250%p" +> + <include + latin:keyboardLayout="@xml/kbd_rows_phone_shift" /> +</Keyboard> diff --git a/java/res/xml-sw768dp/kbd_key_styles.xml b/java/res/xml-sw768dp/kbd_key_styles.xml index f16f5b6af..e6ec53dd1 100644 --- a/java/res/xml-sw768dp/kbd_key_styles.xml +++ b/java/res/xml-sw768dp/kbd_key_styles.xml @@ -26,75 +26,87 @@ latin:code="@integer/key_shift" latin:keyIcon="iconShiftKey" latin:keyIconShifted="iconShiftedShiftKey" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="sticky" /> <key-style latin:styleName="deleteKeyStyle" latin:code="@integer/key_delete" latin:keyIcon="iconDeleteKey" - latin:backgroundType="functional" - latin:isRepeatable="true" /> + latin:keyActionFlags="isRepeatable|noKeyPreview" + latin:backgroundType="functional" /> <key-style latin:styleName="returnKeyStyle" latin:code="@integer/key_return" latin:keyIcon="iconReturnKey" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <key-style latin:styleName="spaceKeyStyle" - latin:code="@integer/key_space" /> + latin:code="@integer/key_space" + latin:keyActionFlags="noKeyPreview" /> <key-style latin:styleName="nonSpecialBackgroundSpaceKeyStyle" - latin:code="@integer/key_space" /> + latin:code="@integer/key_space" + latin:keyActionFlags="noKeyPreview" /> <key-style latin:styleName="smileyKeyStyle" latin:keyLabel=":-)" latin:keyOutputText=":-) " - latin:keyLabelOption="hasPopupHint" + latin:keyLabelFlags="hasPopupHint" latin:moreKeys="@string/more_keys_for_smiley" latin:maxMoreKeysColumn="5" /> <key-style - latin:styleName="settingsKeyStyle" - latin:code="@integer/key_settings" - latin:keyIcon="iconSettingsKey" - latin:backgroundType="functional" /> - <key-style latin:styleName="shortcutKeyStyle" latin:code="@integer/key_shortcut" latin:keyIcon="iconShortcutKey" + latin:keyActionFlags="noKeyPreview|altCodeWhileTyping" + latin:altCode="@integer/key_space" + latin:backgroundType="functional" /> + <key-style + latin:styleName="settingsKeyStyle" + latin:code="@integer/key_settings" + latin:keyIcon="iconSettingsKey" + latin:keyActionFlags="noKeyPreview|altCodeWhileTyping" + latin:altCode="@integer/key_space" latin:backgroundType="functional" /> <key-style latin:styleName="tabKeyStyle" latin:code="@integer/key_tab" latin:keyLabel="@string/label_tab_key" - latin:keyLabelOption="fontNormal" + latin:keyLabelFlags="fontNormal" latin:backgroundType="functional" /> <key-style latin:styleName="toSymbolKeyStyle" latin:code="@integer/key_switch_alpha_symbol" latin:keyLabel="@string/label_to_symbol_key" - latin:keyLabelOption="fontNormal" + latin:keyLabelFlags="fontNormal" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <key-style latin:styleName="toAlphaKeyStyle" latin:code="@integer/key_switch_alpha_symbol" latin:keyLabel="@string/label_to_alpha_key" - latin:keyLabelOption="fontNormal" + latin:keyLabelFlags="fontNormal" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <key-style latin:styleName="toMoreSymbolKeyStyle" latin:code="@integer/key_shift" latin:keyLabel="@string/label_to_more_symbol_for_tablet_key" - latin:keyLabelOption="fontNormal" + latin:keyLabelFlags="fontNormal" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <key-style latin:styleName="backFromMoreSymbolKeyStyle" latin:code="@integer/key_shift" latin:keyLabel="@string/label_to_symbol_key" - latin:keyLabelOption="fontNormal" + latin:keyLabelFlags="fontNormal" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <key-style latin:styleName="comKeyStyle" latin:keyLabel="@string/keylabel_for_popular_domain" - latin:keyLabelOption="fontNormal|hasPopupHint" + latin:keyLabelFlags="fontNormal|hasPopupHint" latin:keyOutputText="@string/keylabel_for_popular_domain" latin:moreKeys="@string/more_keys_for_popular_domain" /> </merge> diff --git a/java/res/xml-sw768dp/kbd_number.xml b/java/res/xml-sw768dp/kbd_number.xml index 369e91a77..74ce854cf 100644 --- a/java/res/xml-sw768dp/kbd_number.xml +++ b/java/res/xml-sw768dp/kbd_number.xml @@ -23,206 +23,5 @@ latin:keyWidth="13.250%p" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> - <include - latin:keyboardLayout="@xml/kbd_numkey_styles" /> - <switch> - <case - latin:passwordInput="true" - > - <Row> - <Key - latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" - latin:keyWidth="11.172%p" /> - <Key - latin:keyStyle="num1KeyStyle" - latin:keyXPos="32.076%p" /> - <Key - latin:keyStyle="num2KeyStyle" /> - <Key - latin:keyStyle="num3KeyStyle" /> - <Key - latin:keyStyle="deleteKeyStyle" - latin:keyXPos="-11.172%p" - latin:keyWidth="fillRight" /> - </Row> - <Row> - <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> - <Spacer - latin:keyWidth="32.076%p" /> - <Key - latin:keyStyle="num4KeyStyle" /> - <Key - latin:keyStyle="num5KeyStyle" /> - <Key - latin:keyStyle="num6KeyStyle" /> - <Key - latin:keyStyle="returnKeyStyle" - latin:keyXPos="-11.172%p" - latin:keyWidth="fillRight" /> - </Row> - <Row> - <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> - <Spacer - latin:keyWidth="32.076%p" /> - <Key - latin:keyStyle="num7KeyStyle" /> - <Key - latin:keyStyle="num8KeyStyle" /> - <Key - latin:keyStyle="num9KeyStyle" /> - <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> - <Spacer - latin:keyWidth="0%p" /> - </Row> - <Row> - <Spacer - latin:keyXPos="32.076%p" /> - <Key - latin:keyStyle="num0KeyStyle" /> - <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> - <Spacer - latin:keyWidth="0%p" /> - </Row> - </case> - <!-- latin:passwordInput="false" --> - <default> - <Row> - <Key - latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" - latin:keyWidth="11.172%p" /> - <Key - latin:keyLabel="-" - latin:keyStyle="numKeyStyle" - latin:keyXPos="13.829%p" - latin:keyWidth="8.047%p" /> - <Key - latin:keyLabel="+" - latin:keyStyle="numKeyStyle" - latin:keyWidth="8.047%p" /> - <Key - latin:keyLabel="." - latin:keyStyle="numKeyStyle" - latin:keyWidth="8.047%p" /> - <Key - latin:keyLabel="1" - latin:keyStyle="numKeyStyle" - latin:keyXPos="43.125%p" /> - <Key - latin:keyLabel="2" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyLabel="3" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyStyle="deleteKeyStyle" - latin:keyXPos="-11.172%p" - latin:keyWidth="fillRight" /> - </Row> - <Row> - <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> - <Spacer - latin:keyWidth="13.829%p" /> - <Key - latin:keyStyle="numStarKeyStyle" - latin:keyWidth="8.047%p" /> - <Key - latin:keyLabel="/" - latin:keyStyle="numKeyStyle" - latin:keyWidth="8.047%p" /> - <Key - latin:keyLabel="," - latin:keyStyle="numKeyStyle" - latin:keyWidth="8.047%p" /> - <Key - latin:keyLabel="4" - latin:keyStyle="numKeyStyle" - latin:keyXPos="43.125%p" /> - <Key - latin:keyLabel="5" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyLabel="6" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyStyle="returnKeyStyle" - latin:keyXPos="-11.172%p" - latin:keyWidth="fillRight" /> - </Row> - <Row> - <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> - <Spacer - latin:keyWidth="13.829%p" /> - <Key - latin:keyLabel="(" - latin:keyStyle="numKeyStyle" - latin:keyWidth="8.047%p" /> - <Key - latin:keyLabel=")" - latin:keyStyle="numKeyStyle" - latin:keyWidth="8.047%p" /> - <Key - latin:keyLabel="=" - latin:keyStyle="numKeyStyle" - latin:keyWidth="8.047%p" /> - <Key - latin:keyLabel="7" - latin:keyStyle="numKeyStyle" - latin:keyXPos="43.125%p" /> - <Key - latin:keyLabel="8" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyLabel="9" - latin:keyStyle="numKeyStyle" /> - <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> - <Spacer - latin:keyWidth="0%p" /> - </Row> - <Row> - <switch> - <case latin:hasSettingsKey="true"> - <Key - latin:keyStyle="settingsKeyStyle" - latin:keyWidth="8.047%p" /> - </case> - <default> - <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> - <Spacer - latin:keyWidth="8.047%p" /> - </default> - </switch> - <Key - latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle" - latin:keyXPos="13.829%p" - latin:keyWidth="24.140%p" /> - <Key - latin:keyStyle="numStarKeyStyle" - latin:keyXPos="43.125%p" /> - <Key - latin:keyLabel="0" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyLabel="#" - latin:keyStyle="numKeyStyle" /> - <switch> - <case - latin:shortcutKeyEnabled="true" - > - <Key - latin:keyStyle="shortcutKeyStyle" - latin:keyXPos="-8.047%p" - latin:keyWidth="fillRight" /> - </case> - <default> - <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> - <Spacer - latin:keyWidth="0%p" /> - </default> - </switch> - </Row> - </default> - </switch> + latin:keyboardLayout="@xml/kbd_rows_number" /> </Keyboard> diff --git a/java/res/xml-sw768dp/kbd_phone.xml b/java/res/xml-sw768dp/kbd_phone.xml index e55b1841a..0a9b8b53a 100644 --- a/java/res/xml-sw768dp/kbd_phone.xml +++ b/java/res/xml-sw768dp/kbd_phone.xml @@ -23,122 +23,5 @@ latin:keyWidth="13.250%p" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> - <include - latin:keyboardLayout="@xml/kbd_numkey_styles" /> - <Row> - <Key - latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" - latin:keyWidth="11.172%p" /> - <Key - latin:keyLabel="-" - latin:keyStyle="numKeyStyle" - latin:keyXPos="20.400%p" - latin:keyWidth="8.047%p" /> - <Key - latin:keyLabel="+" - latin:keyStyle="numKeyStyle" - latin:keyWidth="8.047%p" /> - <Key - latin:keyStyle="num1KeyStyle" - latin:keyXPos="43.125%p" /> - <Key - latin:keyStyle="num2KeyStyle" /> - <Key - latin:keyStyle="num3KeyStyle" /> - <Key - latin:keyStyle="deleteKeyStyle" - latin:keyXPos="-11.172%p" - latin:keyWidth="fillRight" /> - </Row> - <Row> - <Key - latin:keyStyle="toMoreSymbolKeyStyle" - latin:keyWidth="11.172%p" /> - <Key - latin:keyLabel="," - latin:keyStyle="numKeyStyle" - latin:keyXPos="20.400%p" - latin:keyWidth="8.047%p" /> - <Key - latin:keyLabel="." - latin:keyStyle="numKeyStyle" - latin:keyWidth="8.047%p" /> - <Key - latin:keyStyle="num4KeyStyle" - latin:keyXPos="43.125%p" /> - <Key - latin:keyStyle="num5KeyStyle" /> - <Key - latin:keyStyle="num6KeyStyle" /> - <Key - latin:keyStyle="returnKeyStyle" - latin:keyXPos="-11.172%p" - latin:keyWidth="fillRight" /> - </Row> - <Row> - <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> - <Spacer - latin:keyWidth="20.400%p" /> - <Key - latin:keyLabel="(" - latin:keyStyle="numKeyStyle" - latin:keyWidth="8.047%p" /> - <Key - latin:keyLabel=")" - latin:keyStyle="numKeyStyle" - latin:keyWidth="8.047%p" /> - <Key - latin:keyStyle="num7KeyStyle" - latin:keyXPos="43.125%p" /> - <Key - latin:keyStyle="num8KeyStyle" /> - <Key - latin:keyStyle="num9KeyStyle" /> - <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> - <Spacer - latin:keyWidth="0%p" /> - </Row> - <Row> - <switch> - <case latin:hasSettingsKey="true"> - <Key - latin:keyStyle="settingsKeyStyle" - latin:keyWidth="8.047%p" /> - </case> - <default> - <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> - <Spacer - latin:keyWidth="8.047%p" /> - </default> - </switch> - <Key - latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle" - latin:keyXPos="20.400%p" - latin:keyWidth="16.084%p" /> - <Key - latin:keyStyle="numStarKeyStyle" - latin:keyXPos="43.125%p" /> - <Key - latin:keyStyle="num0KeyStyle" /> - <Key - latin:keyLabel="#" - latin:keyStyle="numKeyStyle" /> - <switch> - <case - latin:shortcutKeyEnabled="true" - > - <Key - latin:keyStyle="shortcutKeyStyle" - latin:keyXPos="-8.047%p" - latin:keyWidth="fillRight" /> - </case> - <default> - <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> - <Spacer - latin:keyWidth="0%p" /> - </default> - </switch> - </Row> + latin:keyboardLayout="@xml/kbd_rows_phone" /> </Keyboard> diff --git a/java/res/xml-sw768dp/kbd_phone_shift.xml b/java/res/xml-sw768dp/kbd_phone_shift.xml index 46f67d311..055d70cd2 100644 --- a/java/res/xml-sw768dp/kbd_phone_shift.xml +++ b/java/res/xml-sw768dp/kbd_phone_shift.xml @@ -23,136 +23,5 @@ latin:keyWidth="13.250%p" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> - <include - latin:keyboardLayout="@xml/kbd_numkey_styles" /> - <Row> - <Key - latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" - latin:keyWidth="11.172%p" /> - <Key - latin:keyLabel="-" - latin:keyStyle="numKeyStyle" - latin:keyXPos="13.829%p" - latin:keyWidth="8.047%p" /> - <Key - latin:keyLabel="+" - latin:keyStyle="numKeyStyle" - latin:keyWidth="8.047%p" /> - <Key - latin:code="44" - latin:keyLabel="@string/label_pause_key" - latin:keyLabelOption="followKeyHintLabelRatio|autoXScale" - latin:keyWidth="8.047%p" /> - <Key - latin:keyStyle="num1KeyStyle" - latin:keyXPos="43.125%p" /> - <Key - latin:keyStyle="num2KeyStyle" /> - <Key - latin:keyStyle="num3KeyStyle" /> - <Key - latin:keyStyle="deleteKeyStyle" - latin:keyXPos="-11.172%p" - latin:keyWidth="fillRight" /> - </Row> - <Row> - <Key - latin:keyStyle="backFromMoreSymbolKeyStyle" - latin:keyWidth="11.172%p" /> - <Key - latin:keyLabel="," - latin:keyStyle="numKeyStyle" - latin:keyXPos="13.829%p" - latin:keyWidth="8.047%p" /> - <Key - latin:keyLabel="." - latin:keyStyle="numKeyStyle" - latin:keyWidth="8.047%p" /> - <Key - latin:code="59" - latin:keyLabel="@string/label_wait_key" - latin:keyLabelOption="followKeyHintLabelRatio|autoXScale" - latin:keyWidth="8.047%p" /> - <Key - latin:keyStyle="num4KeyStyle" - latin:keyXPos="43.125%p" /> - <Key - latin:keyStyle="num5KeyStyle" /> - <Key - latin:keyStyle="num6KeyStyle" /> - <Key - latin:keyStyle="returnKeyStyle" - latin:keyXPos="-11.172%p" - latin:keyWidth="fillRight" /> - </Row> - <Row> - <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> - <Spacer - latin:keyWidth="13.829%p" /> - <Key - latin:keyLabel="(" - latin:keyStyle="numKeyStyle" - latin:keyWidth="8.047%p" /> - <Key - latin:keyLabel=")" - latin:keyStyle="numKeyStyle" - latin:keyWidth="8.047%p" /> - <Key - latin:keyLabel="N" - latin:keyStyle="numKeyStyle" - latin:keyWidth="8.047%p" /> - <Key - latin:keyStyle="num7KeyStyle" - latin:keyXPos="43.125%p" /> - <Key - latin:keyStyle="num8KeyStyle" /> - <Key - latin:keyStyle="num9KeyStyle" /> - <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> - <Spacer - latin:keyWidth="0%p" /> - </Row> - <Row> - <switch> - <case latin:hasSettingsKey="true"> - <Key - latin:keyStyle="settingsKeyStyle" - latin:keyWidth="8.047%p" /> - </case> - <default> - <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> - <Spacer - latin:keyWidth="8.047%p" /> - </default> - </switch> - <Key - latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle" - latin:keyXPos="13.829%p" - latin:keyWidth="24.140%p" /> - <Key - latin:keyStyle="numStarKeyStyle" - latin:keyXPos="43.125%p" /> - <Key - latin:keyStyle="num0KeyStyle" /> - <Key - latin:keyLabel="#" - latin:keyStyle="numKeyStyle" /> - <switch> - <case - latin:shortcutKeyEnabled="true" - > - <Key - latin:keyStyle="shortcutKeyStyle" - latin:keyXPos="-8.047%p" - latin:keyWidth="fillRight" /> - </case> - <default> - <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> - <Spacer - latin:keyWidth="0%p" /> - </default> - </switch> - </Row> + latin:keyboardLayout="@xml/kbd_rows_phone_shift" /> </Keyboard> diff --git a/java/res/xml-sw768dp/kbd_qwerty_row1.xml b/java/res/xml-sw768dp/kbd_qwerty_row1.xml index 14b8bddfb..de9101331 100644 --- a/java/res/xml-sw768dp/kbd_qwerty_row1.xml +++ b/java/res/xml-sw768dp/kbd_qwerty_row1.xml @@ -26,7 +26,7 @@ > <Key latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="7.969%p" /> <Key latin:keyLabel="q" diff --git a/java/res/xml-sw768dp/kbd_qwerty_row2.xml b/java/res/xml-sw768dp/kbd_qwerty_row2.xml index 2c312a328..1129ecdba 100644 --- a/java/res/xml-sw768dp/kbd_qwerty_row2.xml +++ b/java/res/xml-sw768dp/kbd_qwerty_row2.xml @@ -26,7 +26,7 @@ > <Key latin:keyStyle="toSymbolKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="11.172%p"/> <Key latin:keyLabel="a" diff --git a/java/res/xml-sw768dp/kbd_qwerty_row4.xml b/java/res/xml-sw768dp/kbd_qwerty_row4.xml index e35e47d83..1f00dff84 100644 --- a/java/res/xml-sw768dp/kbd_qwerty_row4.xml +++ b/java/res/xml-sw768dp/kbd_qwerty_row4.xml @@ -57,7 +57,7 @@ > <Key latin:keyLabel=":" - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="+" latin:moreKeys="+" /> </case> @@ -76,7 +76,7 @@ <default> <Key latin:keyLabel="/" - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="\@" latin:moreKeys="\@" /> </default> diff --git a/java/res/xml-sw768dp/kbd_row3_comma_period.xml b/java/res/xml-sw768dp/kbd_row3_comma_period.xml index b84443078..6a95ca1a3 100644 --- a/java/res/xml-sw768dp/kbd_row3_comma_period.xml +++ b/java/res/xml-sw768dp/kbd_row3_comma_period.xml @@ -33,12 +33,12 @@ <default> <Key latin:keyLabel="," - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="!" latin:moreKeys="!" /> <Key latin:keyLabel="." - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="\?" latin:moreKeys="\?" /> </default> diff --git a/java/res/xml-sw768dp/kbd_row4_apostrophe_dash.xml b/java/res/xml-sw768dp/kbd_row4_apostrophe_dash.xml index 9536e81da..4eb82d24a 100644 --- a/java/res/xml-sw768dp/kbd_row4_apostrophe_dash.xml +++ b/java/res/xml-sw768dp/kbd_row4_apostrophe_dash.xml @@ -33,14 +33,14 @@ > <Key latin:keyLabel="/" - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel=":" latin:moreKeys=":" /> </case> <default> <Key latin:keyLabel="@string/keylabel_for_apostrophe" - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="@string/keyhintlabel_for_apostrophe" latin:moreKeys="@string/more_keys_for_apostrophe" /> </default> @@ -55,7 +55,7 @@ <default> <Key latin:keyLabel="@string/keylabel_for_dash" - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="@string/keyhintlabel_for_dash" latin:moreKeys="@string/more_keys_for_dash" /> </default> diff --git a/java/res/xml-sw768dp/kbd_rows_arabic.xml b/java/res/xml-sw768dp/kbd_rows_arabic.xml index 7ec36fd94..412d5d98a 100644 --- a/java/res/xml-sw768dp/kbd_rows_arabic.xml +++ b/java/res/xml-sw768dp/kbd_rows_arabic.xml @@ -28,7 +28,7 @@ > <Key latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="7.500%p" /> <!-- \u0636: ARABIC LETTER DAD --> <Key @@ -84,7 +84,7 @@ > <Key latin:keyStyle="toSymbolKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="9.375%p" /> <!-- \u0634: ARABIC LETTER SHEEN \u069c: ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE --> diff --git a/java/res/xml-sw768dp/kbd_rows_azerty.xml b/java/res/xml-sw768dp/kbd_rows_azerty.xml index 4659d9924..3edfb7e5b 100644 --- a/java/res/xml-sw768dp/kbd_rows_azerty.xml +++ b/java/res/xml-sw768dp/kbd_rows_azerty.xml @@ -28,7 +28,7 @@ > <Key latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="7.969%p" /> <Key latin:keyLabel="a" @@ -70,7 +70,7 @@ > <Key latin:keyStyle="toSymbolKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="10.167%p" /> <Key latin:keyLabel="q" @@ -127,7 +127,7 @@ latin:moreKeys="@string/more_keys_for_n" /> <Key latin:keyLabel="\'" - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel=":" latin:moreKeys=":" /> <switch> @@ -142,12 +142,12 @@ <default> <Key latin:keyLabel="," - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="!" latin:moreKeys="!" /> <Key latin:keyLabel="." - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="\?" latin:moreKeys="\?" /> </default> diff --git a/java/res/xml-sw768dp/kbd_rows_hebrew.xml b/java/res/xml-sw768dp/kbd_rows_hebrew.xml index 27b39d1ae..5f4b556b6 100644 --- a/java/res/xml-sw768dp/kbd_rows_hebrew.xml +++ b/java/res/xml-sw768dp/kbd_rows_hebrew.xml @@ -28,7 +28,7 @@ > <Key latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="7.969%p" /> <include latin:keyboardLayout="@xml/kbd_row4_apostrophe_dash" /> @@ -58,7 +58,7 @@ > <Key latin:keyStyle="toSymbolKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="11.172%p" /> <Key latin:keyLabel="ש" /> diff --git a/java/res/xml-sw768dp/kbd_rows_number.xml b/java/res/xml-sw768dp/kbd_rows_number.xml new file mode 100644 index 000000000..1268987b5 --- /dev/null +++ b/java/res/xml-sw768dp/kbd_rows_number.xml @@ -0,0 +1,227 @@ +<?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. +*/ +--> + +<merge + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" +> + <include + latin:keyboardLayout="@xml/kbd_key_styles" /> + <include + latin:keyboardLayout="@xml/kbd_numkey_styles" /> + <switch> + <case + latin:passwordInput="true" + > + <Row> + <Key + latin:keyStyle="numTabKeyStyle" + latin:keyLabelFlags="alignLeft" + latin:keyWidth="11.172%p" /> + <Key + latin:keyStyle="num1KeyStyle" + latin:keyXPos="32.076%p" /> + <Key + latin:keyStyle="num2KeyStyle" /> + <Key + latin:keyStyle="num3KeyStyle" /> + <Key + latin:keyStyle="deleteKeyStyle" + latin:keyXPos="-11.172%p" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="32.076%p" /> + <Key + latin:keyStyle="num4KeyStyle" /> + <Key + latin:keyStyle="num5KeyStyle" /> + <Key + latin:keyStyle="num6KeyStyle" /> + <Key + latin:keyStyle="returnKeyStyle" + latin:keyXPos="-11.172%p" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="32.076%p" /> + <Key + latin:keyStyle="num7KeyStyle" /> + <Key + latin:keyStyle="num8KeyStyle" /> + <Key + latin:keyStyle="num9KeyStyle" /> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="0%p" /> + </Row> + <Row> + <Spacer + latin:keyXPos="32.076%p" /> + <Key + latin:keyStyle="num0KeyStyle" /> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="0%p" /> + </Row> + </case> + <!-- latin:passwordInput="false" --> + <default> + <Row> + <Key + latin:keyStyle="tabKeyStyle" + latin:keyLabelFlags="alignLeft" + latin:keyWidth="11.172%p" /> + <Key + latin:keyLabel="-" + latin:keyStyle="numKeyStyle" + latin:keyXPos="13.829%p" + latin:keyWidth="8.047%p" /> + <Key + latin:keyLabel="+" + latin:keyStyle="numKeyStyle" + latin:keyWidth="8.047%p" /> + <Key + latin:keyLabel="." + latin:keyStyle="numKeyStyle" + latin:keyWidth="8.047%p" /> + <Key + latin:keyLabel="1" + latin:keyStyle="numKeyStyle" + latin:keyXPos="43.125%p" /> + <Key + latin:keyLabel="2" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyLabel="3" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyStyle="deleteKeyStyle" + latin:keyXPos="-11.172%p" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="13.829%p" /> + <Key + latin:keyStyle="numStarKeyStyle" + latin:keyWidth="8.047%p" /> + <Key + latin:keyLabel="/" + latin:keyStyle="numKeyStyle" + latin:keyWidth="8.047%p" /> + <Key + latin:keyLabel="," + latin:keyStyle="numKeyStyle" + latin:keyWidth="8.047%p" /> + <Key + latin:keyLabel="4" + latin:keyStyle="numKeyStyle" + latin:keyXPos="43.125%p" /> + <Key + latin:keyLabel="5" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyLabel="6" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyStyle="returnKeyStyle" + latin:keyXPos="-11.172%p" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="13.829%p" /> + <Key + latin:keyLabel="(" + latin:keyStyle="numKeyStyle" + latin:keyWidth="8.047%p" /> + <Key + latin:keyLabel=")" + latin:keyStyle="numKeyStyle" + latin:keyWidth="8.047%p" /> + <Key + latin:keyLabel="=" + latin:keyStyle="numKeyStyle" + latin:keyWidth="8.047%p" /> + <Key + latin:keyLabel="7" + latin:keyStyle="numKeyStyle" + latin:keyXPos="43.125%p" /> + <Key + latin:keyLabel="8" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyLabel="9" + latin:keyStyle="numKeyStyle" /> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="0%p" /> + </Row> + <Row> + <switch> + <case latin:hasSettingsKey="true"> + <Key + latin:keyStyle="settingsKeyStyle" + latin:keyWidth="8.047%p" /> + </case> + <default> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="8.047%p" /> + </default> + </switch> + <Key + latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle" + latin:keyXPos="13.829%p" + latin:keyWidth="24.140%p" /> + <Key + latin:keyStyle="numStarKeyStyle" + latin:keyXPos="43.125%p" /> + <Key + latin:keyLabel="0" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyLabel="#" + latin:keyStyle="numKeyStyle" /> + <switch> + <case + latin:shortcutKeyEnabled="true" + > + <Key + latin:keyStyle="shortcutKeyStyle" + latin:keyXPos="-8.047%p" + latin:keyWidth="fillRight" /> + </case> + <default> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="0%p" /> + </default> + </switch> + </Row> + </default> + </switch> +</merge> diff --git a/java/res/xml-sw768dp/kbd_rows_phone.xml b/java/res/xml-sw768dp/kbd_rows_phone.xml new file mode 100644 index 000000000..1320cf0ba --- /dev/null +++ b/java/res/xml-sw768dp/kbd_rows_phone.xml @@ -0,0 +1,143 @@ +<?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. +*/ +--> + +<merge + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" +> + <include + latin:keyboardLayout="@xml/kbd_key_styles" /> + <include + latin:keyboardLayout="@xml/kbd_numkey_styles" /> + <Row> + <Key + latin:keyStyle="numTabKeyStyle" + latin:keyLabelFlags="alignLeft" + latin:keyWidth="11.172%p" /> + <Key + latin:keyLabel="-" + latin:keyStyle="numKeyStyle" + latin:keyXPos="20.400%p" + latin:keyWidth="8.047%p" /> + <Key + latin:keyLabel="+" + latin:keyStyle="numKeyStyle" + latin:keyWidth="8.047%p" /> + <Key + latin:keyStyle="num1KeyStyle" + latin:keyXPos="43.125%p" /> + <Key + latin:keyStyle="num2KeyStyle" /> + <Key + latin:keyStyle="num3KeyStyle" /> + <Key + latin:keyStyle="deleteKeyStyle" + latin:keyXPos="-11.172%p" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <Key + latin:keyStyle="toMoreSymbolKeyStyle" + latin:keyWidth="11.172%p" /> + <Key + latin:keyLabel="," + latin:keyStyle="numKeyStyle" + latin:keyXPos="20.400%p" + latin:keyWidth="8.047%p" /> + <Key + latin:keyLabel="." + latin:keyStyle="numKeyStyle" + latin:keyWidth="8.047%p" /> + <Key + latin:keyStyle="num4KeyStyle" + latin:keyXPos="43.125%p" /> + <Key + latin:keyStyle="num5KeyStyle" /> + <Key + latin:keyStyle="num6KeyStyle" /> + <Key + latin:keyStyle="returnKeyStyle" + latin:keyXPos="-11.172%p" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="20.400%p" /> + <Key + latin:keyLabel="(" + latin:keyStyle="numKeyStyle" + latin:keyWidth="8.047%p" /> + <Key + latin:keyLabel=")" + latin:keyStyle="numKeyStyle" + latin:keyWidth="8.047%p" /> + <Key + latin:keyStyle="num7KeyStyle" + latin:keyXPos="43.125%p" /> + <Key + latin:keyStyle="num8KeyStyle" /> + <Key + latin:keyStyle="num9KeyStyle" /> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="0%p" /> + </Row> + <Row> + <switch> + <case latin:hasSettingsKey="true"> + <Key + latin:keyStyle="settingsKeyStyle" + latin:keyWidth="8.047%p" /> + </case> + <default> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="8.047%p" /> + </default> + </switch> + <Key + latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle" + latin:keyXPos="20.400%p" + latin:keyWidth="16.084%p" /> + <Key + latin:keyStyle="numStarKeyStyle" + latin:keyXPos="43.125%p" /> + <Key + latin:keyStyle="num0KeyStyle" /> + <Key + latin:keyLabel="#" + latin:keyStyle="numKeyStyle" /> + <switch> + <case + latin:shortcutKeyEnabled="true" + > + <Key + latin:keyStyle="shortcutKeyStyle" + latin:keyXPos="-8.047%p" + latin:keyWidth="fillRight" /> + </case> + <default> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="0%p" /> + </default> + </switch> + </Row> +</merge> diff --git a/java/res/xml-sw768dp/kbd_rows_phone_shift.xml b/java/res/xml-sw768dp/kbd_rows_phone_shift.xml new file mode 100644 index 000000000..e749790a0 --- /dev/null +++ b/java/res/xml-sw768dp/kbd_rows_phone_shift.xml @@ -0,0 +1,153 @@ +<?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. +*/ +--> + +<merge + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" +> + <include + latin:keyboardLayout="@xml/kbd_key_styles" /> + <include + latin:keyboardLayout="@xml/kbd_numkey_styles" /> + <Row> + <Key + latin:keyStyle="numTabKeyStyle" + latin:keyLabelFlags="alignLeft" + latin:keyWidth="11.172%p" /> + <Key + latin:keyLabel="-" + latin:keyStyle="numKeyStyle" + latin:keyXPos="13.829%p" + latin:keyWidth="8.047%p" /> + <Key + latin:keyLabel="+" + latin:keyStyle="numKeyStyle" + latin:keyWidth="8.047%p" /> + <Key + latin:keyStyle="numPauseKeyStyle" + latin:keyWidth="8.047%p" /> + <Key + latin:keyStyle="num1KeyStyle" + latin:keyXPos="43.125%p" /> + <Key + latin:keyStyle="num2KeyStyle" /> + <Key + latin:keyStyle="num3KeyStyle" /> + <Key + latin:keyStyle="deleteKeyStyle" + latin:keyXPos="-11.172%p" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <Key + latin:keyStyle="backFromMoreSymbolKeyStyle" + latin:keyWidth="11.172%p" /> + <Key + latin:keyLabel="," + latin:keyStyle="numKeyStyle" + latin:keyXPos="13.829%p" + latin:keyWidth="8.047%p" /> + <Key + latin:keyLabel="." + latin:keyStyle="numKeyStyle" + latin:keyWidth="8.047%p" /> + <Key + latin:keyStyle="numWaitKeyStyle" + latin:keyWidth="8.047%p" /> + <Key + latin:keyStyle="num4KeyStyle" + latin:keyXPos="43.125%p" /> + <Key + latin:keyStyle="num5KeyStyle" /> + <Key + latin:keyStyle="num6KeyStyle" /> + <Key + latin:keyStyle="returnKeyStyle" + latin:keyXPos="-11.172%p" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="13.829%p" /> + <Key + latin:keyLabel="(" + latin:keyStyle="numKeyStyle" + latin:keyWidth="8.047%p" /> + <Key + latin:keyLabel=")" + latin:keyStyle="numKeyStyle" + latin:keyWidth="8.047%p" /> + <Key + latin:keyLabel="N" + latin:keyStyle="numKeyStyle" + latin:keyWidth="8.047%p" /> + <Key + latin:keyStyle="num7KeyStyle" + latin:keyXPos="43.125%p" /> + <Key + latin:keyStyle="num8KeyStyle" /> + <Key + latin:keyStyle="num9KeyStyle" /> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="0%p" /> + </Row> + <Row> + <switch> + <case latin:hasSettingsKey="true"> + <Key + latin:keyStyle="settingsKeyStyle" + latin:keyWidth="8.047%p" /> + </case> + <default> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="8.047%p" /> + </default> + </switch> + <Key + latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle" + latin:keyXPos="13.829%p" + latin:keyWidth="24.140%p" /> + <Key + latin:keyStyle="numStarKeyStyle" + latin:keyXPos="43.125%p" /> + <Key + latin:keyStyle="num0KeyStyle" /> + <Key + latin:keyLabel="#" + latin:keyStyle="numKeyStyle" /> + <switch> + <case + latin:shortcutKeyEnabled="true" + > + <Key + latin:keyStyle="shortcutKeyStyle" + latin:keyXPos="-8.047%p" + latin:keyWidth="fillRight" /> + </case> + <default> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="0%p" /> + </default> + </switch> + </Row> +</merge> diff --git a/java/res/xml-sw768dp/kbd_rows_qwertz.xml b/java/res/xml-sw768dp/kbd_rows_qwertz.xml index 82e0dd09c..3c02c8f62 100644 --- a/java/res/xml-sw768dp/kbd_rows_qwertz.xml +++ b/java/res/xml-sw768dp/kbd_rows_qwertz.xml @@ -28,7 +28,7 @@ > <Key latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="7.969%p" /> <Key latin:keyLabel="q" @@ -103,12 +103,12 @@ <default> <Key latin:keyLabel="," - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="!" latin:moreKeys="!" /> <Key latin:keyLabel="." - latin:keyLabelOption="hasUppercaseLetter" + latin:keyLabelFlags="hasUppercaseLetter" latin:keyHintLabel="\?" latin:moreKeys="\?" /> </default> diff --git a/java/res/xml-sw768dp/kbd_rows_russian.xml b/java/res/xml-sw768dp/kbd_rows_russian.xml index e5f556958..eb0baf95d 100644 --- a/java/res/xml-sw768dp/kbd_rows_russian.xml +++ b/java/res/xml-sw768dp/kbd_rows_russian.xml @@ -28,7 +28,7 @@ > <Key latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" /> + latin:keyLabelFlags="alignLeft" /> <Key latin:keyLabel="й" /> <Key @@ -63,7 +63,7 @@ > <Key latin:keyStyle="toSymbolKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="9.375%p" /> <Key latin:keyLabel="ф" /> diff --git a/java/res/xml-sw768dp/kbd_rows_scandinavian.xml b/java/res/xml-sw768dp/kbd_rows_scandinavian.xml index b9d168036..c2dead230 100644 --- a/java/res/xml-sw768dp/kbd_rows_scandinavian.xml +++ b/java/res/xml-sw768dp/kbd_rows_scandinavian.xml @@ -28,7 +28,7 @@ > <Key latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="7.500%p" /> <Key latin:keyLabel="q" @@ -72,7 +72,7 @@ > <Key latin:keyStyle="toSymbolKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="9.375%p" /> <Key latin:keyLabel="a" diff --git a/java/res/xml-sw768dp/kbd_rows_serbian.xml b/java/res/xml-sw768dp/kbd_rows_serbian.xml index c07176ef6..0b1773e40 100644 --- a/java/res/xml-sw768dp/kbd_rows_serbian.xml +++ b/java/res/xml-sw768dp/kbd_rows_serbian.xml @@ -28,7 +28,7 @@ > <Key latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" /> + latin:keyLabelFlags="alignLeft" /> <Key latin:keyLabel="љ" /> <Key @@ -62,7 +62,7 @@ > <Key latin:keyStyle="toSymbolKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="11.172%p" /> <Key latin:keyLabel="а" /> diff --git a/java/res/xml-sw768dp/kbd_rows_spanish.xml b/java/res/xml-sw768dp/kbd_rows_spanish.xml index c737f400a..7e543b2fb 100644 --- a/java/res/xml-sw768dp/kbd_rows_spanish.xml +++ b/java/res/xml-sw768dp/kbd_rows_spanish.xml @@ -30,7 +30,7 @@ > <Key latin:keyStyle="toSymbolKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="10.167%p" /> <Key latin:keyLabel="a" diff --git a/java/res/xml-sw768dp/kbd_rows_symbols.xml b/java/res/xml-sw768dp/kbd_rows_symbols.xml index 987b10cdc..641fe1934 100644 --- a/java/res/xml-sw768dp/kbd_rows_symbols.xml +++ b/java/res/xml-sw768dp/kbd_rows_symbols.xml @@ -30,7 +30,7 @@ > <Key latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="7.969%p" /> <Key latin:keyLabel="@string/keylabel_for_symbols_1" @@ -72,7 +72,7 @@ > <Key latin:keyStyle="toAlphaKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="11.172%p" /> <Key latin:keyLabel="#" /> diff --git a/java/res/xml-sw768dp/kbd_rows_symbols_shift.xml b/java/res/xml-sw768dp/kbd_rows_symbols_shift.xml index 9a9c3a276..f6b47a86f 100644 --- a/java/res/xml-sw768dp/kbd_rows_symbols_shift.xml +++ b/java/res/xml-sw768dp/kbd_rows_symbols_shift.xml @@ -30,7 +30,7 @@ > <Key latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="7.969%p" /> <Key latin:keyLabel="~" /> @@ -65,7 +65,7 @@ > <Key latin:keyStyle="toAlphaKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="11.172%p" /> <Key latin:keyStyle="moreCurrency1KeyStyle" /> diff --git a/java/res/xml/kbd_key_styles.xml b/java/res/xml/kbd_key_styles.xml index 453b05dff..5714e09c5 100644 --- a/java/res/xml/kbd_key_styles.xml +++ b/java/res/xml/kbd_key_styles.xml @@ -28,7 +28,7 @@ > <key-style latin:styleName="f1PopupStyle" - latin:keyLabelOption="hasPopupHint" + latin:keyLabelFlags="hasPopupHint" latin:moreKeys="@string/more_keys_for_f1" latin:backgroundType="functional" /> </case> @@ -38,7 +38,7 @@ > <key-style latin:styleName="f1PopupStyle" - latin:keyLabelOption="hasPopupHint" + latin:keyLabelFlags="hasPopupHint" latin:moreKeys="@string/more_keys_for_f1_settings" latin:backgroundType="functional" /> </case> @@ -48,7 +48,7 @@ > <key-style latin:styleName="f1PopupStyle" - latin:keyLabelOption="hasPopupHint" + latin:keyLabelFlags="hasPopupHint" latin:moreKeys="@string/more_keys_for_f1_navigate" latin:backgroundType="functional" /> </case> @@ -56,7 +56,7 @@ <default> <key-style latin:styleName="f1PopupStyle" - latin:keyLabelOption="hasPopupHint" + latin:keyLabelFlags="hasPopupHint" latin:moreKeys="@string/more_keys_for_f1" latin:backgroundType="functional" /> </default> @@ -67,13 +67,14 @@ latin:code="@integer/key_shift" latin:keyIcon="iconShiftKey" latin:keyIconShifted="iconShiftedShiftKey" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="sticky" /> <key-style latin:styleName="deleteKeyStyle" latin:code="@integer/key_delete" latin:keyIcon="iconDeleteKey" - latin:backgroundType="functional" - latin:isRepeatable="true" /> + latin:keyActionFlags="isRepeatable|noKeyPreview" + latin:backgroundType="functional" /> <!-- Return key style --> <switch> <case @@ -84,7 +85,7 @@ latin:styleName="returnKeyStyle" latin:keyLabel=":-)" latin:keyOutputText=":-) " - latin:keyLabelOption="hasPopupHint" + latin:keyLabelFlags="hasPopupHint" latin:moreKeys="@string/more_keys_for_smiley" latin:maxMoreKeysColumn="5" latin:backgroundType="functional" /> @@ -96,7 +97,8 @@ latin:styleName="returnKeyStyle" latin:code="@integer/key_return" latin:keyLabel="@string/label_go_key" - latin:keyLabelOption="autoXScale" + latin:keyLabelFlags="autoXScale" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="action" /> </case> <case @@ -106,7 +108,8 @@ latin:styleName="returnKeyStyle" latin:code="@integer/key_return" latin:keyLabel="@string/label_next_key" - latin:keyLabelOption="autoXScale" + latin:keyLabelFlags="autoXScale" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="action" /> </case> <case @@ -116,7 +119,8 @@ latin:styleName="returnKeyStyle" latin:code="@integer/key_return" latin:keyLabel="@string/label_done_key" - latin:keyLabelOption="autoXScale" + latin:keyLabelFlags="autoXScale" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="action" /> </case> <case @@ -126,7 +130,8 @@ latin:styleName="returnKeyStyle" latin:code="@integer/key_return" latin:keyLabel="@string/label_send_key" - latin:keyLabelOption="autoXScale" + latin:keyLabelFlags="autoXScale" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="action" /> </case> <case @@ -136,6 +141,8 @@ latin:styleName="returnKeyStyle" latin:code="@integer/key_return" latin:keyIcon="iconSearchKey" + latin:keyLabelFlags="autoXScale" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="action" /> </case> <default> @@ -143,22 +150,28 @@ latin:styleName="returnKeyStyle" latin:code="@integer/key_return" latin:keyIcon="iconReturnKey" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> </default> </switch> <key-style latin:styleName="spaceKeyStyle" latin:code="@integer/key_space" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <key-style latin:styleName="shortcutKeyStyle" latin:code="@integer/key_shortcut" latin:keyIcon="iconShortcutKey" + latin:keyActionFlags="noKeyPreview|altCodeWhileTyping" + latin:altCode="@integer/key_space" latin:parentStyle="f1PopupStyle" /> <key-style latin:styleName="settingsKeyStyle" latin:code="@integer/key_settings" latin:keyIcon="iconSettingsKey" + latin:keyActionFlags="noKeyPreview|altCodeWhileTyping" + latin:altCode="@integer/key_space" latin:backgroundType="functional" /> <key-style latin:styleName="tabKeyStyle" @@ -186,7 +199,8 @@ latin:code="@integer/key_switch_alpha_symbol" latin:keyIcon="iconShortcutForLabel" latin:keyLabel="@string/label_to_symbol_with_microphone_key" - latin:keyLabelOption="withIconRight" + latin:keyLabelFlags="withIconRight" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> </case> <default> @@ -194,6 +208,7 @@ latin:styleName="toSymbolKeyStyle" latin:code="@integer/key_switch_alpha_symbol" latin:keyLabel="@string/label_to_symbol_key" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> </default> </switch> @@ -201,22 +216,25 @@ latin:styleName="toAlphaKeyStyle" latin:code="@integer/key_switch_alpha_symbol" latin:keyLabel="@string/label_to_alpha_key" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <key-style latin:styleName="toMoreSymbolKeyStyle" latin:code="@integer/key_shift" latin:keyLabel="@string/label_to_more_symbol_key" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <key-style latin:styleName="backFromMoreSymbolKeyStyle" latin:code="@integer/key_shift" latin:keyLabel="@string/label_to_symbol_key" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <key-style latin:styleName="punctuationKeyStyle" latin:keyLabel="." latin:keyHintLabel="@string/keyhintlabel_for_punctuation" - latin:keyLabelOption="hasPopupHint" + latin:keyLabelFlags="hasPopupHint" latin:moreKeys="@string/more_keys_for_punctuation" latin:maxMoreKeysColumn="@integer/mini_keyboard_column_for_punctuation" latin:backgroundType="functional" /> diff --git a/java/res/xml/kbd_numkey_styles.xml b/java/res/xml/kbd_numkey_styles.xml index 5d5439906..c2ff4d50f 100644 --- a/java/res/xml/kbd_numkey_styles.xml +++ b/java/res/xml/kbd_numkey_styles.xml @@ -22,18 +22,24 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <key-style + latin:styleName="numKeyBaseStyle" + latin:keyActionFlags="noKeyPreview" /> + <key-style latin:styleName="numKeyStyle" - latin:keyLabelOption="largeLetter|followKeyLetterRatio" /> + latin:keyLabelFlags="largeLetter|followKeyLetterRatio" + latin:parentStyle="numKeyBaseStyle" /> <key-style latin:styleName="numModeKeyStyle" - latin:keyLabelOption="fontNormal|followKeyLetterRatio" /> + latin:keyLabelFlags="fontNormal|followKeyLetterRatio" + latin:parentStyle="numKeyBaseStyle" /> <key-style latin:styleName="numFunctionalKeyStyle" - latin:keyLabelOption="largeLetter|followKeyLetterRatio" - latin:backgroundType="functional" /> + latin:keyLabelFlags="largeLetter|followKeyLetterRatio" + latin:backgroundType="functional" + latin:parentStyle="numKeyBaseStyle" /> <key-style latin:styleName="numberKeyStyle" - latin:keyLabelOption="alignLeftOfCenter|hasHintLabel" + latin:keyLabelFlags="alignLeftOfCenter|hasHintLabel" latin:parentStyle="numKeyStyle" /> <key-style latin:styleName="num0KeyStyle" @@ -100,7 +106,24 @@ latin:keyLabel="@string/label_to_phone_numeric_key" latin:parentStyle="numModeKeyStyle" /> <key-style + latin:styleName="numPauseKeyStyle" + latin:code="44" + latin:keyLabel="@string/label_pause_key" + latin:keyLabelFlags="followKeyHintLabelRatio|autoXScale" + latin:parentStyle="numKeyBaseStyle" /> + <key-style + latin:styleName="numWaitKeyStyle" + latin:code="59" + latin:keyLabel="@string/label_wait_key" + latin:keyLabelFlags="followKeyHintLabelRatio|autoXScale" + latin:parentStyle="numKeyBaseStyle" /> + <key-style + latin:styleName="numTabKeyStyle" + latin:keyActionFlags="noKeyPreview" + latin:parentStyle="tabKeyStyle" /> + <key-style latin:styleName="numSpaceKeyStyle" latin:code="@integer/key_space" - latin:keyIcon="iconSpaceKey" /> + latin:keyIcon="iconSpaceKey" + latin:parentStyle="numKeyBaseStyle" /> </merge> diff --git a/java/res/xml/kbd_rows_phone_shift.xml b/java/res/xml/kbd_rows_phone_shift.xml index 3c283d3e6..b39e2da8d 100644 --- a/java/res/xml/kbd_rows_phone_shift.xml +++ b/java/res/xml/kbd_rows_phone_shift.xml @@ -42,13 +42,12 @@ </Row> <Row> <Key - latin:keyLabel="N" /> + latin:keyLabel="N" + latin:keyStyle="numKeyBaseStyle" /> <!-- Pause is a comma. Check PhoneNumberUtils.java to see if this has changed. --> <Key - latin:code="44" - latin:keyLabel="@string/label_pause_key" - latin:keyLabelOption="followKeyHintLabelRatio|autoXScale" /> + latin:keyStyle="numPauseKeyStyle" /> <Key latin:keyLabel="," latin:keyStyle="numKeyStyle" /> @@ -62,9 +61,7 @@ latin:keyStyle="numStarKeyStyle" /> <!-- Wait is a semicolon. --> <Key - latin:code="59" - latin:keyLabel="@string/label_wait_key" - latin:keyLabelOption="followKeyHintLabelRatio|autoXScale" /> + latin:keyStyle="numWaitKeyStyle" /> <Key latin:keyLabel="#" latin:keyStyle="numKeyStyle" /> diff --git a/java/res/xml/kbd_symbols_shift_row4.xml b/java/res/xml/kbd_symbols_shift_row4.xml index 89e80e5f7..079112c78 100644 --- a/java/res/xml/kbd_symbols_shift_row4.xml +++ b/java/res/xml/kbd_symbols_shift_row4.xml @@ -33,7 +33,7 @@ latin:keyStyle="toAlphaKeyStyle" latin:keyWidth="15%p" /> <!-- Note: Neither DroidSans nor Roboto have a glyph for ‟ Double high-reversed-9 quotation mark U+201F. --> - <!-- latin:keyLabelOption="hasPopupHint" --> + <!-- latin:keyLabelFlags="hasPopupHint" --> <!-- latin:moreKeys="‟" --> <Key latin:keyLabel="„" @@ -56,7 +56,7 @@ <include latin:keyboardLayout="@xml/kbd_settings_or_tab" /> <!-- Note: Neither DroidSans nor Roboto have a glyph for ‟ Double high-reversed-9 quotation mark U+201F. --> - <!-- latin:keyLabelOption="hasPopupHint" --> + <!-- latin:keyLabelFlags="hasPopupHint" --> <!-- latin:moreKeys="‟" --> <Key latin:keyLabel="„" diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml index 6184add4d..2b2c00c17 100644 --- a/java/res/xml/method.xml +++ b/java/res/xml/method.xml @@ -20,7 +20,7 @@ <!-- The attributes in this XML file provide configuration information --> <!-- for the Input Method Manager. --> -<!-- Keyboard: en_US, en_GB, ar, cs, da, de, de(QWERTY), es, es_US, fi, fr, fr_CA, fr_CH, hr, hu, it, iw, nb, nl, pl, pt, ru, sr, sv, tr --> +<!-- Keyboard: en_US, en_GB, ar, cs, da, de, de(QWERTY), es, es_US, et, fi, fr, fr_CA, fr_CH, hr, hu, it, iw, lt, lv, nb, nl, pl, pt, ru, sr, sv, tr --> <!-- TODO: use <lang>_keyboard icon instead of a common keyboard icon. --> <!-- If IME doesn't have an applicable subtype, the first subtype will be used as a default subtype.--> @@ -77,6 +77,12 @@ /> <subtype android:icon="@drawable/ic_subtype_keyboard" android:label="@string/subtype_generic" + android:imeSubtypeLocale="et" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection" + /> + <subtype android:icon="@drawable/ic_subtype_keyboard" + android:label="@string/subtype_generic" android:imeSubtypeLocale="fi" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection" @@ -126,6 +132,18 @@ /> <subtype android:icon="@drawable/ic_subtype_keyboard" android:label="@string/subtype_generic" + android:imeSubtypeLocale="lt" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection" + /> + <subtype android:icon="@drawable/ic_subtype_keyboard" + android:label="@string/subtype_generic" + android:imeSubtypeLocale="lv" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection" + /> + <subtype android:icon="@drawable/ic_subtype_keyboard" + android:label="@string/subtype_generic" android:imeSubtypeLocale="nb" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection" diff --git a/java/res/xml/spell_checker_settings.xml b/java/res/xml/spell_checker_settings.xml index f402555c9..222b98b6b 100644 --- a/java/res/xml/spell_checker_settings.xml +++ b/java/res/xml/spell_checker_settings.xml @@ -18,9 +18,9 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:title="@string/android_spell_checker_settings"> <CheckBoxPreference - android:key="use_proximity" - android:title="@string/use_proximity_option_title" - android:summary="@string/use_proximity_option_summary" + android:key="pref_spellcheck_use_contacts" + android:title="@string/use_contacts_for_spellchecking_option_title" + android:summary="@string/use_contacts_for_spellchecking_option_summary" android:persistent="true" android:defaultValue="true" /> </PreferenceScreen> diff --git a/java/res/xml/spellchecker.xml b/java/res/xml/spellchecker.xml index 30fac5b20..b48dc52cd 100644 --- a/java/res/xml/spellchecker.xml +++ b/java/res/xml/spellchecker.xml @@ -21,7 +21,8 @@ <!-- for the spell checker --> <spell-checker xmlns:android="http://schemas.android.com/apk/res/android" - android:label="@string/spell_checker_service_name"> + android:label="@string/spell_checker_service_name" + android:settingsActivity="com.android.inputmethod.latin.spellcheck.SpellCheckerSettingsActivity"> <subtype android:label="@string/subtype_generic" android:subtypeLocale="en" @@ -42,4 +43,16 @@ android:label="@string/subtype_generic" android:subtypeLocale="es" /> + <subtype + android:label="@string/subtype_generic" + android:subtypeLocale="ru" + /> + <subtype + android:label="@string/subtype_generic" + android:subtypeLocale="cs" + /> + <subtype + android:label="@string/subtype_generic" + android:subtypeLocale="nl" + /> </spell-checker> diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java index 46663327d..1836f27b3 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java @@ -120,8 +120,8 @@ public class AccessibilityUtils { * * @return {@code true} if the device should obscure password characters. */ - public boolean shouldObscureInput(EditorInfo attribute) { - if (attribute == null) + public boolean shouldObscureInput(EditorInfo editorInfo) { + if (editorInfo == null) return false; // The user can optionally force speaking passwords. @@ -137,7 +137,7 @@ public class AccessibilityUtils { return false; // Don't speak if the IME is connected to a password field. - return InputTypeCompatUtils.isPasswordInputType(attribute.inputType); + return InputTypeCompatUtils.isPasswordInputType(editorInfo.inputType); } /** @@ -171,11 +171,11 @@ public class AccessibilityUtils { * Handles speaking the "connect a headset to hear passwords" notification * when connecting to a password field. * - * @param attribute The input connection's editor info attribute. + * @param editorInfo The input connection's editor info attribute. * @param restarting Whether the connection is being restarted. */ - public void onStartInputViewInternal(EditorInfo attribute, boolean restarting) { - if (shouldObscureInput(attribute)) { + public void onStartInputViewInternal(EditorInfo editorInfo, boolean restarting) { + if (shouldObscureInput(editorInfo)) { final CharSequence text = mContext.getText(R.string.spoken_use_headphones); speak(text); } diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java index cef82267f..4cb2f20b9 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java @@ -29,7 +29,6 @@ import android.view.inputmethod.EditorInfo; import com.android.inputmethod.compat.AccessibilityEventCompatUtils; import com.android.inputmethod.compat.MotionEventCompatUtils; import com.android.inputmethod.keyboard.Key; -import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.LatinKeyboardView; import com.android.inputmethod.keyboard.PointerTracker; @@ -42,7 +41,7 @@ public class AccessibleKeyboardViewProxy { private LatinKeyboardView mView; private AccessibleKeyboardActionListener mListener; - private int mLastHoverKeyIndex = KeyDetector.NOT_A_KEY; + private Key mLastHoverKey = null; public static void init(InputMethodService inputMethod, SharedPreferences prefs) { sInstance.initInternal(inputMethod, prefs); @@ -81,7 +80,7 @@ public class AccessibleKeyboardViewProxy { switch (event.getEventType()) { case AccessibilityEventCompatUtils.TYPE_VIEW_HOVER_ENTER: - final Key key = tracker.getKey(mLastHoverKeyIndex); + final Key key = mLastHoverKey; if (key == null) break; @@ -130,12 +129,12 @@ public class AccessibleKeyboardViewProxy { switch (event.getAction()) { case MotionEventCompatUtils.ACTION_HOVER_ENTER: case MotionEventCompatUtils.ACTION_HOVER_MOVE: - final int keyIndex = tracker.getKeyIndexOn(x, y); + final Key key = tracker.getKeyOn(x, y); - if (keyIndex != mLastHoverKeyIndex) { - fireKeyHoverEvent(tracker, mLastHoverKeyIndex, false); - mLastHoverKeyIndex = keyIndex; - fireKeyHoverEvent(tracker, mLastHoverKeyIndex, true); + if (key != mLastHoverKey) { + fireKeyHoverEvent(tracker, mLastHoverKey, false); + mLastHoverKey = key; + fireKeyHoverEvent(tracker, mLastHoverKey, true); } return true; @@ -144,7 +143,7 @@ public class AccessibleKeyboardViewProxy { return false; } - private void fireKeyHoverEvent(PointerTracker tracker, int keyIndex, boolean entering) { + private void fireKeyHoverEvent(PointerTracker tracker, Key key, boolean entering) { if (mListener == null) { Log.e(TAG, "No accessible keyboard action listener set!"); return; @@ -155,11 +154,6 @@ public class AccessibleKeyboardViewProxy { return; } - if (keyIndex == KeyDetector.NOT_A_KEY) - return; - - final Key key = tracker.getKey(keyIndex); - if (key == null) return; diff --git a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java index 7302830d4..e01262c20 100644 --- a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java +++ b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java @@ -136,16 +136,14 @@ public class KeyCodeDescriptionMapper { if (!TextUtils.isEmpty(key.mLabel)) { final String label = key.mLabel.toString().trim(); + // First, attempt to map the label to a pre-defined description. if (mKeyLabelMap.containsKey(label)) { return context.getString(mKeyLabelMap.get(label)); - } else if (label.length() == 1 - || (keyboard.isManualTemporaryUpperCase() && !TextUtils - .isEmpty(key.mHintLabel))) { - return getDescriptionForKeyCode(context, keyboard, key, shouldObscure); - } else { - return label; } - } else if (key.mCode != Keyboard.CODE_DUMMY) { + } + + // Just attempt to speak the description. + if (key.mCode != Keyboard.CODE_DUMMY) { return getDescriptionForKeyCode(context, keyboard, key, shouldObscure); } @@ -187,11 +185,14 @@ public class KeyCodeDescriptionMapper { * @return the key code for the specified key */ private int getCorrectKeyCode(Keyboard keyboard, Key key) { - if (keyboard.isManualTemporaryUpperCase() && !TextUtils.isEmpty(key.mHintLabel)) { + // If keyboard is in manual temporary upper case state and key has + // manual temporary uppercase letter as key hint letter, alternate + // character code should be sent. + if (keyboard.isManualTemporaryUpperCase() && key.hasUppercaseLetter() + && !TextUtils.isEmpty(key.mHintLabel)) { return key.mHintLabel.charAt(0); - } else { - return key.mCode; } + return key.mCode; } /** diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java index 51dc4cd37..0e5f8c80a 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java @@ -153,8 +153,7 @@ public class InputMethodManagerCompatWrapper { return Utils.getInputMethodInfo(this, mLatinImePackageName); } - @SuppressWarnings("unused") - private InputMethodSubtypeCompatWrapper getLastResortSubtype(String mode) { + private static InputMethodSubtypeCompatWrapper getLastResortSubtype(String mode) { if (VOICE_MODE.equals(mode) && !FORCE_ENABLE_VOICE_EVEN_WITH_NO_VOICE_SUBTYPES) return null; Locale inputLocale = SubtypeSwitcher.getInstance().getInputLocale(); diff --git a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java index 161ef09b8..f476d83b4 100644 --- a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java +++ b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java @@ -50,19 +50,19 @@ public class SuggestionSpanUtils { .getConstructor(CLASS_SuggestionSpan, INPUT_TYPE_SuggestionSpan); public static final Field FIELD_FLAG_AUTO_CORRECTION = CompatUtils.getField(CLASS_SuggestionSpan, "FLAG_AUTO_CORRECTION"); - public static final Field FIELD_SUGGESTION_MAX_SIZE + public static final Field FIELD_SUGGESTIONS_MAX_SIZE = CompatUtils.getField(CLASS_SuggestionSpan, "SUGGESTIONS_MAX_SIZE"); public static final Integer OBJ_FLAG_AUTO_CORRECTION = (Integer) CompatUtils .getFieldValue(null, null, FIELD_FLAG_AUTO_CORRECTION);; - public static final Integer OBJ_SUGGESTION_MAX_SIZE = (Integer) CompatUtils - .getFieldValue(null, null, FIELD_SUGGESTION_MAX_SIZE);; + public static final Integer OBJ_SUGGESTIONS_MAX_SIZE = (Integer) CompatUtils + .getFieldValue(null, null, FIELD_SUGGESTIONS_MAX_SIZE);; static { SUGGESTION_SPAN_IS_SUPPORTED = CLASS_SuggestionSpan != null && CONSTRUCTOR_SuggestionSpan != null; if (LatinImeLogger.sDBG) { if (SUGGESTION_SPAN_IS_SUPPORTED - && (OBJ_FLAG_AUTO_CORRECTION == null || OBJ_SUGGESTION_MAX_SIZE == null)) { + && (OBJ_FLAG_AUTO_CORRECTION == null || OBJ_SUGGESTIONS_MAX_SIZE == null)) { throw new RuntimeException("Field is accidentially null."); } } @@ -71,7 +71,7 @@ public class SuggestionSpanUtils { public static CharSequence getTextWithAutoCorrectionIndicatorUnderline( Context context, CharSequence text) { if (TextUtils.isEmpty(text) || CONSTRUCTOR_SuggestionSpan == null - || OBJ_FLAG_AUTO_CORRECTION == null || OBJ_SUGGESTION_MAX_SIZE == null) { + || OBJ_FLAG_AUTO_CORRECTION == null || OBJ_SUGGESTIONS_MAX_SIZE == null) { return text; } final Spannable spannable = text instanceof Spannable @@ -94,7 +94,7 @@ public class SuggestionSpanUtils { if (TextUtils.isEmpty(pickedWord) || CONSTRUCTOR_SuggestionSpan == null || suggestedWords == null || suggestedWords.size() == 0 || suggestedWords.getInfo(0).isObsoleteSuggestedWord() - || OBJ_SUGGESTION_MAX_SIZE == null) { + || OBJ_SUGGESTIONS_MAX_SIZE == null) { return pickedWord; } @@ -106,7 +106,7 @@ public class SuggestionSpanUtils { } final ArrayList<String> suggestionsList = new ArrayList<String>(); for (int i = 0; i < suggestedWords.size(); ++i) { - if (suggestionsList.size() >= OBJ_SUGGESTION_MAX_SIZE) { + if (suggestionsList.size() >= OBJ_SUGGESTIONS_MAX_SIZE) { break; } final CharSequence word = suggestedWords.getWord(i); diff --git a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java index 3f8c2ef8f..a013ebca9 100644 --- a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java +++ b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java @@ -695,12 +695,12 @@ public class VoiceProxy implements VoiceInput.UiListener { && !mVoiceInput.isBlacklistedField(fieldContext); } - private boolean shouldShowVoiceButton(FieldContext fieldContext, EditorInfo attribute) { + private boolean shouldShowVoiceButton(FieldContext fieldContext, EditorInfo editorInfo) { @SuppressWarnings("deprecation") final boolean noMic = Utils.inPrivateImeOptions(null, - LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, attribute) + LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo) || Utils.inPrivateImeOptions(mService.getPackageName(), - LatinIME.IME_OPTION_NO_MICROPHONE, attribute); + LatinIME.IME_OPTION_NO_MICROPHONE, editorInfo); return ENABLE_VOICE_BUTTON && fieldCanDoVoice(fieldContext) && !noMic && SpeechRecognizer.isRecognitionAvailable(mService); } @@ -709,7 +709,7 @@ public class VoiceProxy implements VoiceInput.UiListener { return SpeechRecognizer.isRecognitionAvailable(context); } - public void loadSettings(EditorInfo attribute, SharedPreferences sp) { + public void loadSettings(EditorInfo editorInfo, SharedPreferences sp) { if (!VOICE_INSTALLED) { return; } @@ -723,7 +723,7 @@ public class VoiceProxy implements VoiceInput.UiListener { final String voiceMode = sp.getString(PREF_VOICE_MODE, mService.getString(R.string.voice_mode_main)); mVoiceButtonEnabled = !voiceMode.equals(mService.getString(R.string.voice_mode_off)) - && shouldShowVoiceButton(makeFieldContext(), attribute); + && shouldShowVoiceButton(makeFieldContext(), editorInfo); mVoiceButtonOnPrimary = voiceMode.equals(mService.getString(R.string.voice_mode_main)); } diff --git a/java/src/com/android/inputmethod/deprecated/voice/FieldContext.java b/java/src/com/android/inputmethod/deprecated/voice/FieldContext.java index 3c79cc218..fd2cf3d25 100644 --- a/java/src/com/android/inputmethod/deprecated/voice/FieldContext.java +++ b/java/src/com/android/inputmethod/deprecated/voice/FieldContext.java @@ -43,10 +43,10 @@ public class FieldContext { Bundle mFieldInfo; - public FieldContext(InputConnection conn, EditorInfo info, + public FieldContext(InputConnection conn, EditorInfo editorInfo, String selectedLanguage, String[] enabledLanguages) { mFieldInfo = new Bundle(); - addEditorInfoToBundle(info, mFieldInfo); + addEditorInfoToBundle(editorInfo, mFieldInfo); addInputConnectionToBundle(conn, mFieldInfo); addLanguageInfoToBundle(selectedLanguage, enabledLanguages, mFieldInfo); if (DBG) Log.i("FieldContext", "Bundle = " + mFieldInfo.toString()); diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index f1ae0b313..b2b68f0ad 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -46,27 +46,28 @@ public class Key { * The key code (unicode or custom code) that this key generates. */ public final int mCode; + public final int mAltCode; /** Label to display */ public final CharSequence mLabel; /** Hint label to display on the key in conjunction with the label */ public final CharSequence mHintLabel; - /** Option of the label */ - private final int mLabelOption; - private static final int LABEL_OPTION_ALIGN_LEFT = 0x01; - private static final int LABEL_OPTION_ALIGN_RIGHT = 0x02; - private static final int LABEL_OPTION_ALIGN_LEFT_OF_CENTER = 0x08; - private static final int LABEL_OPTION_LARGE_LETTER = 0x10; - private static final int LABEL_OPTION_FONT_NORMAL = 0x20; - private static final int LABEL_OPTION_FONT_MONO_SPACE = 0x40; - private static final int LABEL_OPTION_FOLLOW_KEY_LETTER_RATIO = 0x80; - private static final int LABEL_OPTION_FOLLOW_KEY_HINT_LABEL_RATIO = 0x100; - private static final int LABEL_OPTION_HAS_POPUP_HINT = 0x200; - private static final int LABEL_OPTION_HAS_UPPERCASE_LETTER = 0x400; - private static final int LABEL_OPTION_HAS_HINT_LABEL = 0x800; - private static final int LABEL_OPTION_WITH_ICON_LEFT = 0x1000; - private static final int LABEL_OPTION_WITH_ICON_RIGHT = 0x2000; - private static final int LABEL_OPTION_AUTO_X_SCALE = 0x4000; + /** Flags of the label */ + private final int mLabelFlags; + private static final int LABEL_FLAGS_ALIGN_LEFT = 0x01; + private static final int LABEL_FLAGS_ALIGN_RIGHT = 0x02; + private static final int LABEL_FLAGS_ALIGN_LEFT_OF_CENTER = 0x08; + private static final int LABEL_FLAGS_LARGE_LETTER = 0x10; + private static final int LABEL_FLAGS_FONT_NORMAL = 0x20; + private static final int LABEL_FLAGS_FONT_MONO_SPACE = 0x40; + private static final int LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO = 0x80; + private static final int LABEL_FLAGS_FOLLOW_KEY_HINT_LABEL_RATIO = 0x100; + private static final int LABEL_FLAGS_HAS_POPUP_HINT = 0x200; + private static final int LABEL_FLAGS_HAS_UPPERCASE_LETTER = 0x400; + private static final int LABEL_FLAGS_HAS_HINT_LABEL = 0x800; + private static final int LABEL_FLAGS_WITH_ICON_LEFT = 0x1000; + private static final int LABEL_FLAGS_WITH_ICON_RIGHT = 0x2000; + private static final int LABEL_FLAGS_AUTO_X_SCALE = 0x4000; /** Icon to display instead of a label. Icon takes precedence over a label */ private Drawable mIcon; @@ -105,8 +106,10 @@ public class Key { public static final int BACKGROUND_TYPE_ACTION = 2; public static final int BACKGROUND_TYPE_STICKY = 3; - /** Whether this key repeats itself when held down */ - public final boolean mRepeatable; + private final int mActionFlags; + private static final int ACTION_FLAGS_IS_REPEATABLE = 0x01; + private static final int ACTION_FLAGS_NO_KEY_PREVIEW = 0x02; + private static final int ACTION_FLAGS_ALT_CODE_WHILE_TYPING = 0x04; /** The current pressed state of this key */ private boolean mPressed; @@ -181,14 +184,15 @@ public class Key { mVisualInsetsLeft = mVisualInsetsRight = 0; mWidth = width - mHorizontalGap; mHintLabel = hintLabel; - mLabelOption = 0; + mLabelFlags = 0; mBackgroundType = BACKGROUND_TYPE_NORMAL; - mRepeatable = false; + mActionFlags = 0; mMoreKeys = null; mMaxMoreKeysColumn = 0; mLabel = label; mOutputText = outputText; mCode = code; + mAltCode = Keyboard.CODE_DUMMY; mIcon = icon; // Horizontal gap is divided equally to both sides of the key. mX = x + mHorizontalGap / 2; @@ -223,7 +227,7 @@ public class Key { if (style == null) throw new ParseException("Unknown key style: " + styleName, parser); } else { - style = keyStyles.getEmptyKeyStyle(); + style = KeyStyles.getEmptyKeyStyle(); } final float keyXPos = row.getKeyX(keyAttr); @@ -254,8 +258,7 @@ public class Key { mBackgroundType = style.getInt(keyAttr, R.styleable.Keyboard_Key_backgroundType, BACKGROUND_TYPE_NORMAL); - mRepeatable = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_isRepeatable, false); - mEnabled = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_enabled, true); + mActionFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyActionFlags, 0); final KeyboardIconsSet iconsSet = params.mIconsSet; mVisualInsetsLeft = (int) KeyboardBuilder.getDimensionOrFraction(keyAttr, @@ -275,7 +278,7 @@ public class Key { mHintLabel = style.getText(keyAttr, R.styleable.Keyboard_Key_keyHintLabel); mLabel = style.getText(keyAttr, R.styleable.Keyboard_Key_keyLabel); - mLabelOption = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelOption, 0); + mLabelFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags, 0); mOutputText = style.getText(keyAttr, R.styleable.Keyboard_Key_keyOutputText); // Choose the first letter of the label as primary code if not // specified. @@ -289,6 +292,8 @@ public class Key { } else { mCode = Keyboard.CODE_DUMMY; } + mAltCode = style.getInt(keyAttr, + R.styleable.Keyboard_Key_altCode, Keyboard.CODE_DUMMY); keyAttr.recycle(); } @@ -317,11 +322,31 @@ public class Key { return false; } + public boolean isShift() { + return mCode == Keyboard.CODE_SHIFT; + } + + public boolean isModifier() { + return mCode == Keyboard.CODE_SHIFT || mCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL; + } + + public boolean isRepeatable() { + return (mActionFlags & ACTION_FLAGS_IS_REPEATABLE) != 0; + } + + public boolean noKeyPreview() { + return (mActionFlags & ACTION_FLAGS_NO_KEY_PREVIEW) != 0; + } + + public boolean altCodeWhileTyping() { + return (mActionFlags & ACTION_FLAGS_ALT_CODE_WHILE_TYPING) != 0; + } + public Typeface selectTypeface(Typeface defaultTypeface) { // TODO: Handle "bold" here too? - if ((mLabelOption & LABEL_OPTION_FONT_NORMAL) != 0) { + if ((mLabelFlags & LABEL_FLAGS_FONT_NORMAL) != 0) { return Typeface.DEFAULT; - } else if ((mLabelOption & LABEL_OPTION_FONT_MONO_SPACE) != 0) { + } else if ((mLabelFlags & LABEL_FLAGS_FONT_MONO_SPACE) != 0) { return Typeface.MONOSPACE; } else { return defaultTypeface; @@ -330,12 +355,12 @@ public class Key { public int selectTextSize(int letter, int largeLetter, int label, int hintLabel) { if (mLabel.length() > 1 - && (mLabelOption & (LABEL_OPTION_FOLLOW_KEY_LETTER_RATIO - | LABEL_OPTION_FOLLOW_KEY_HINT_LABEL_RATIO)) == 0) { + && (mLabelFlags & (LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO + | LABEL_FLAGS_FOLLOW_KEY_HINT_LABEL_RATIO)) == 0) { return label; - } else if ((mLabelOption & LABEL_OPTION_FOLLOW_KEY_HINT_LABEL_RATIO) != 0) { + } else if ((mLabelFlags & LABEL_FLAGS_FOLLOW_KEY_HINT_LABEL_RATIO) != 0) { return hintLabel; - } else if ((mLabelOption & LABEL_OPTION_LARGE_LETTER) != 0) { + } else if ((mLabelFlags & LABEL_FLAGS_LARGE_LETTER) != 0) { return largeLetter; } else { return letter; @@ -343,19 +368,19 @@ public class Key { } public boolean isAlignLeft() { - return (mLabelOption & LABEL_OPTION_ALIGN_LEFT) != 0; + return (mLabelFlags & LABEL_FLAGS_ALIGN_LEFT) != 0; } public boolean isAlignRight() { - return (mLabelOption & LABEL_OPTION_ALIGN_RIGHT) != 0; + return (mLabelFlags & LABEL_FLAGS_ALIGN_RIGHT) != 0; } public boolean isAlignLeftOfCenter() { - return (mLabelOption & LABEL_OPTION_ALIGN_LEFT_OF_CENTER) != 0; + return (mLabelFlags & LABEL_FLAGS_ALIGN_LEFT_OF_CENTER) != 0; } public boolean hasPopupHint() { - return (mLabelOption & LABEL_OPTION_HAS_POPUP_HINT) != 0; + return (mLabelFlags & LABEL_FLAGS_HAS_POPUP_HINT) != 0; } public void setNeedsSpecialPopupHint(boolean needsSpecialPopupHint) { @@ -367,23 +392,23 @@ public class Key { } public boolean hasUppercaseLetter() { - return (mLabelOption & LABEL_OPTION_HAS_UPPERCASE_LETTER) != 0; + return (mLabelFlags & LABEL_FLAGS_HAS_UPPERCASE_LETTER) != 0; } public boolean hasHintLabel() { - return (mLabelOption & LABEL_OPTION_HAS_HINT_LABEL) != 0; + return (mLabelFlags & LABEL_FLAGS_HAS_HINT_LABEL) != 0; } public boolean hasLabelWithIconLeft() { - return (mLabelOption & LABEL_OPTION_WITH_ICON_LEFT) != 0; + return (mLabelFlags & LABEL_FLAGS_WITH_ICON_LEFT) != 0; } public boolean hasLabelWithIconRight() { - return (mLabelOption & LABEL_OPTION_WITH_ICON_RIGHT) != 0; + return (mLabelFlags & LABEL_FLAGS_WITH_ICON_RIGHT) != 0; } public boolean needsXScale() { - return (mLabelOption & LABEL_OPTION_AUTO_X_SCALE) != 0; + return (mLabelFlags & LABEL_FLAGS_AUTO_X_SCALE) != 0; } public Drawable getIcon() { diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java index 3298c41cf..2a6e0a2de 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java @@ -26,7 +26,7 @@ public class KeyDetector { private static final boolean DEBUG = false; public static final int NOT_A_CODE = -1; - public static final int NOT_A_KEY = -1; + private static final int NOT_A_KEY = -1; private final int mKeyHysteresisDistanceSquared; @@ -96,22 +96,22 @@ public class KeyDetector { } /** - * Computes maximum size of the array that can contain all nearby key indices returned by - * {@link #getKeyIndexAndNearbyCodes}. + * Computes maximum size of the array that can contain all nearby key codes returned by + * {@link #getKeyAndNearbyCodes}. * - * @return Returns maximum size of the array that can contain all nearby key indices returned - * by {@link #getKeyIndexAndNearbyCodes}. + * @return Returns maximum size of the array that can contain all nearby key codes returned + * by {@link #getKeyAndNearbyCodes}. */ protected int getMaxNearbyKeys() { return MAX_NEARBY_KEYS; } /** - * Allocates array that can hold all key indices returned by {@link #getKeyIndexAndNearbyCodes} + * Allocates array that can hold all key codes returned by {@link #getKeyAndNearbyCodes} * method. The maximum size of the array should be computed by {@link #getMaxNearbyKeys}. * - * @return Allocates and returns an array that can hold all key indices returned by - * {@link #getKeyIndexAndNearbyCodes} method. All elements in the returned array are + * @return Allocates and returns an array that can hold all key codes returned by + * {@link #getKeyAndNearbyCodes} method. All elements in the returned array are * initialized by {@link #NOT_A_CODE} value. */ public int[] newCodeArray() { @@ -180,31 +180,32 @@ public class KeyDetector { } /** - * Finds all possible nearby key indices around a touch event point and returns the nearest key - * index. The algorithm to determine the nearby keys depends on the threshold set by + * Finds all possible nearby key codes around a touch event point and returns the nearest key. + * The algorithm to determine the nearby keys depends on the threshold set by * {@link #setProximityThreshold(int)} and the mode set by * {@link #setProximityCorrectionEnabled(boolean)}. * * @param x The x-coordinate of a touch point * @param y The y-coordinate of a touch point - * @param allCodes All nearby key code except functional key are returned in this array - * @return The nearest key index + * @param allCodes All nearby key codes except functional key are returned in this array + * @return The nearest key */ - public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) { + public Key getKeyAndNearbyCodes(int x, int y, final int[] allCodes) { final List<Key> keys = getKeyboard().mKeys; final int touchX = getTouchX(x); final int touchY = getTouchY(y); initializeNearbyKeys(); - int primaryIndex = NOT_A_KEY; + Key primaryKey = null; for (final int index : mKeyboard.getNearestKeys(touchX, touchY)) { final Key key = keys.get(index); final boolean isOnKey = key.isOnKey(touchX, touchY); final int distance = key.squaredDistanceToEdge(touchX, touchY); if (isOnKey || (mProximityCorrectOn && distance < mProximityThresholdSquare)) { final int insertedPosition = sortNearbyKeys(index, distance, isOnKey); - if (insertedPosition == 0 && isOnKey) - primaryIndex = index; + if (insertedPosition == 0 && isOnKey) { + primaryKey = key; + } } } @@ -212,12 +213,31 @@ public class KeyDetector { getNearbyKeyCodes(allCodes); if (DEBUG) { Log.d(TAG, "x=" + x + " y=" + y - + " primary=" - + (primaryIndex == NOT_A_KEY ? "none" : keys.get(primaryIndex).mCode) - + " codes=" + Arrays.toString(allCodes)); + + " primary=" + printableCode(primaryKey) + + " codes=" + printableCodes(allCodes)); } } - return primaryIndex; + return primaryKey; + } + + public static String printableCode(Key key) { + return key != null ? printableCode(key.mCode) : "none"; + } + + public static String printableCode(int primaryCode) { + if (primaryCode < 0) return String.format("%4d", primaryCode); + if (primaryCode < 0x100) return String.format("\\u%02x", primaryCode); + return String.format("\\u04x", primaryCode); + } + + public static String printableCodes(int[] codes) { + final StringBuilder sb = new StringBuilder(); + for (final int code : codes) { + if (code == NOT_A_CODE) break; + if (sb.length() > 0) sb.append(", "); + sb.append(code); + } + return "[" + sb + "]"; } } diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index 4578507fc..2bc140ed5 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -24,6 +24,7 @@ import com.android.inputmethod.keyboard.internal.KeyboardParams; import com.android.inputmethod.keyboard.internal.KeyboardShiftState; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -65,7 +66,6 @@ public class Keyboard { public static final int CODE_DIGIT0 = '0'; public static final int CODE_PLUS = '+'; - /** Special keys code. These should be aligned with values/keycodes.xml */ public static final int CODE_DUMMY = 0; public static final int CODE_SHIFT = -1; @@ -75,7 +75,6 @@ public class Keyboard { public static final int CODE_DELETE = -5; public static final int CODE_SETTINGS = -6; public static final int CODE_SHORTCUT = -7; - public static final int CODE_HAPTIC_AND_AUDIO_FEEDBACK_ONLY = -98; // Code value representing the code is not specified. public static final int CODE_UNSPECIFIED = -99; @@ -112,10 +111,13 @@ public class Keyboard { public final Map<Key, Drawable> mUnshiftedIcons; public final KeyboardIconsSet mIconsSet; - private final KeyboardShiftState mShiftState = new KeyboardShiftState(); + private final Map<Integer, Key> mKeyCache = new HashMap<Integer, Key>(); private final ProximityInfo mProximityInfo; + // TODO: Remove this variable. + private final KeyboardShiftState mShiftState = new KeyboardShiftState(); + public Keyboard(KeyboardParams params) { mId = params.mId; mThemeId = params.mThemeId; @@ -146,82 +148,69 @@ public class Keyboard { return mProximityInfo; } + public Key getKey(int code) { + final Integer keyCode = code; + if (mKeyCache.containsKey(keyCode)) { + return mKeyCache.get(keyCode); + } + + for (final Key key : mKeys) { + if (key.mCode == code) { + mKeyCache.put(keyCode, key); + return key; + } + } + mKeyCache.put(keyCode, null); + return null; + } + + // TODO: Remove this method. public boolean hasShiftLockKey() { return !mShiftLockKeys.isEmpty(); } - public boolean setShiftLocked(boolean newShiftLockState) { + // TODO: Remove this method. + public void setShiftLocked(boolean newShiftLockState) { for (final Key key : mShiftLockKeys) { // To represent "shift locked" state. The highlight is handled by background image that // might be a StateListDrawable. key.setHighlightOn(newShiftLockState); - // To represent "shifted" state. The key might have a shifted icon. - if (newShiftLockState && mShiftedIcons.containsKey(key)) { - key.setIcon(mShiftedIcons.get(key)); - } else { - key.setIcon(mUnshiftedIcons.get(key)); - } + key.setIcon(newShiftLockState ? mShiftedIcons.get(key) : mUnshiftedIcons.get(key)); } mShiftState.setShiftLocked(newShiftLockState); - return true; } + // TODO: Move this method to KeyboardId. public boolean isShiftLocked() { return mShiftState.isShiftLocked(); } - public boolean isShiftLockShifted() { - return mShiftState.isShiftLockShifted(); - } - - public boolean setShifted(boolean newShiftState) { - for (final Key key : mShiftKeys) { - if (!newShiftState && !mShiftState.isShiftLocked()) { - key.setIcon(mUnshiftedIcons.get(key)); - } else if (newShiftState && !mShiftState.isShiftedOrShiftLocked()) { - key.setIcon(mShiftedIcons.get(key)); + // TODO: Remove this method. + public void setShifted(boolean newShiftState) { + if (!mShiftState.isShiftLocked()) { + for (final Key key : mShiftKeys) { + key.setIcon(newShiftState ? mShiftedIcons.get(key) : mUnshiftedIcons.get(key)); } } - return mShiftState.setShifted(newShiftState); + mShiftState.setShifted(newShiftState); } + // TODO: Move this method to KeyboardId. public boolean isShiftedOrShiftLocked() { return mShiftState.isShiftedOrShiftLocked(); } + // TODO: Remove this method public void setAutomaticTemporaryUpperCase() { - setShifted(true); mShiftState.setAutomaticTemporaryUpperCase(); } - public boolean isAutomaticTemporaryUpperCase() { - return isAlphaKeyboard() && mShiftState.isAutomaticTemporaryUpperCase(); - } - + // TODO: Move this method to KeyboardId. public boolean isManualTemporaryUpperCase() { - return isAlphaKeyboard() && mShiftState.isManualTemporaryUpperCase(); - } - - public boolean isManualTemporaryUpperCaseFromAuto() { - return isAlphaKeyboard() && mShiftState.isManualTemporaryUpperCaseFromAuto(); - } - - public KeyboardShiftState getKeyboardShiftState() { - return mShiftState; - } - - public boolean isAlphaKeyboard() { - return mId.isAlphabetKeyboard(); - } - - public boolean isPhoneKeyboard() { - return mId.isPhoneKeyboard(); - } - - public boolean isNumberKeyboard() { - return mId.isNumberKeyboard(); + return mShiftState.isManualTemporaryUpperCase(); } + // TODO: Remove this method. public CharSequence adjustLabelCase(CharSequence label) { if (isShiftedOrShiftLocked() && !TextUtils.isEmpty(label) && label.length() < 3 && Character.isLowerCase(label.charAt(0))) { diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java index 2e4988fb0..840857778 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java @@ -58,15 +58,15 @@ public class KeyboardId { public final int mImeAction; public final String mXmlName; - public final EditorInfo mAttribute; + public final EditorInfo mEditorInfo; private final int mHashCode; public KeyboardId(String xmlName, int xmlId, Locale locale, int orientation, int width, - int mode, EditorInfo attribute, boolean hasSettingsKey, int f2KeyMode, + int mode, EditorInfo editorInfo, boolean hasSettingsKey, int f2KeyMode, boolean clobberSettingsKey, boolean shortcutKeyEnabled, boolean hasShortcutKey) { - final int inputType = (attribute != null) ? attribute.inputType : 0; - final int imeOptions = (attribute != null) ? attribute.imeOptions : 0; + final int inputType = (editorInfo != null) ? editorInfo.inputType : 0; + final int imeOptions = (editorInfo != null) ? editorInfo.imeOptions : 0; this.mLocale = locale; this.mOrientation = orientation; this.mWidth = width; @@ -89,7 +89,7 @@ public class KeyboardId { EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION); this.mXmlName = xmlName; - this.mAttribute = attribute; + this.mEditorInfo = editorInfo; this.mHashCode = Arrays.hashCode(new Object[] { locale, @@ -109,7 +109,7 @@ public class KeyboardId { } public KeyboardId cloneWithNewXml(String xmlName, int xmlId) { - return new KeyboardId(xmlName, xmlId, mLocale, mOrientation, mWidth, mMode, mAttribute, + return new KeyboardId(xmlName, xmlId, mLocale, mOrientation, mWidth, mMode, mEditorInfo, false, F2KEY_MODE_NONE, false, false, false); } @@ -133,10 +133,6 @@ public class KeyboardId { return mXmlId == R.xml.kbd_phone_shift; } - public boolean isNumberKeyboard() { - return mMode == MODE_NUMBER; - } - @Override public boolean equals(Object other) { return other instanceof KeyboardId && equals((KeyboardId) other); diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index ac718fc62..32aabf928 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -30,8 +30,7 @@ import android.view.View; import android.view.inputmethod.EditorInfo; import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; -import com.android.inputmethod.keyboard.internal.ModifierKeyState; -import com.android.inputmethod.keyboard.internal.ShiftKeyState; +import com.android.inputmethod.keyboard.internal.KeyboardState; import com.android.inputmethod.latin.InputView; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; @@ -69,9 +68,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha private String mPackageName; private Resources mResources; - // TODO: Combine these key state objects with auto mode switch state. - private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift"); - private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol"); + private KeyboardState mState; + private static final int UNSHIFT = 0; + private static final int MANUAL_SHIFT = 1; + private static final int AUTOMATIC_SHIFT = 2; private KeyboardId mMainKeyboardId; private KeyboardId mSymbolsKeyboardId; @@ -88,7 +88,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha private boolean mIsAutoCorrectionActive; // TODO: Encapsulate these state handling to separate class and combine with ShiftKeyState - // and ModifierKeyState. + // and ModifierKeyState into KeyboardState. private static final int SWITCH_STATE_ALPHA = 0; private static final int SWITCH_STATE_SYMBOL_BEGIN = 1; private static final int SWITCH_STATE_SYMBOL = 2; @@ -99,7 +99,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha private static final int SWITCH_STATE_CHORDING_SYMBOL = 6; private int mSwitchState = SWITCH_STATE_ALPHA; - private static String mLayoutSwitchBackSymbols; + private String mLayoutSwitchBackSymbols; private int mThemeIndex = -1; private Context mThemeContext; @@ -118,8 +118,8 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } mIsAlphabetMode = isAlphabetMode(); if (mIsAlphabetMode) { - mIsShiftLocked = isShiftLocked(); - mIsShifted = !mIsShiftLocked && isShiftedOrShiftLocked(); + mIsShiftLocked = mState.isShiftLocked(); + mIsShifted = !mIsShiftLocked && mState.isShiftedOrShiftLocked(); } else { mIsShiftLocked = false; mIsShifted = mCurrentId.equals(mSymbolsShiftedKeyboardId); @@ -143,8 +143,8 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha if (mIsAlphabetMode) { final boolean isAlphabetMode = isAlphabetMode(); - final boolean isShiftLocked = isAlphabetMode && isShiftLocked(); - final boolean isShifted = !isShiftLocked && isShiftedOrShiftLocked(); + final boolean isShiftLocked = isAlphabetMode && mState.isShiftLocked(); + final boolean isShifted = !isShiftLocked && mState.isShiftedOrShiftLocked(); if (mIsShiftLocked != isShiftLocked) { toggleCapsLock(); } else if (mIsShifted != isShifted) { @@ -173,6 +173,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha mResources = ims.getResources(); mPrefs = prefs; mSubtypeSwitcher = SubtypeSwitcher.getInstance(); + mState = new KeyboardState(); setContextThemeWrapper(ims, getKeyboardThemeIndex(ims, prefs)); prefs.registerOnSharedPreferenceChangeListener(this); } @@ -230,7 +231,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha mKeyboardView.setKeyboard(keyboard); mCurrentInputView.setKeyboardGeometry(keyboard.mTopPadding); mCurrentId = keyboard.mId; - mSwitchState = getSwitchState(mCurrentId); + mSwitchState = getSwitchState(); updateShiftLockState(keyboard); mKeyboardView.setKeyPreviewPopupEnabled( Settings.Values.isKeyPreviewPopupEnabled(mPrefs, mResources), @@ -241,8 +242,8 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha updateShiftState(); } - private int getSwitchState(KeyboardId id) { - return id.equals(mMainKeyboardId) ? SWITCH_STATE_ALPHA : SWITCH_STATE_SYMBOL_BEGIN; + private int getSwitchState() { + return isAlphabetMode() ? SWITCH_STATE_ALPHA : SWITCH_STATE_SYMBOL_BEGIN; } private void updateShiftLockState(Keyboard keyboard) { @@ -373,68 +374,43 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } public boolean isShiftedOrShiftLocked() { - LatinKeyboard latinKeyboard = getLatinKeyboard(); - if (latinKeyboard != null) - return latinKeyboard.isShiftedOrShiftLocked(); - return false; - } - - public boolean isShiftLocked() { - LatinKeyboard latinKeyboard = getLatinKeyboard(); - if (latinKeyboard != null) - return latinKeyboard.isShiftLocked(); - return false; - } - - private boolean isShiftLockShifted() { - LatinKeyboard latinKeyboard = getLatinKeyboard(); - if (latinKeyboard != null) - return latinKeyboard.isShiftLockShifted(); - return false; - } - - public boolean isAutomaticTemporaryUpperCase() { - LatinKeyboard latinKeyboard = getLatinKeyboard(); - if (latinKeyboard != null) - return latinKeyboard.isAutomaticTemporaryUpperCase(); - return false; + return mState.isShiftedOrShiftLocked(); } public boolean isManualTemporaryUpperCase() { - LatinKeyboard latinKeyboard = getLatinKeyboard(); - if (latinKeyboard != null) - return latinKeyboard.isManualTemporaryUpperCase(); - return false; - } - - private boolean isManualTemporaryUpperCaseFromAuto() { - LatinKeyboard latinKeyboard = getLatinKeyboard(); - if (latinKeyboard != null) - return latinKeyboard.isManualTemporaryUpperCaseFromAuto(); - return false; + return mState.isManualTemporaryUpperCase(); } - private void setManualTemporaryUpperCase(boolean shifted) { + private void setShifted(int shiftMode) { LatinKeyboard latinKeyboard = getLatinKeyboard(); - if (latinKeyboard != null) { + if (latinKeyboard == null) + return; + if (shiftMode == AUTOMATIC_SHIFT) { + mState.setAutomaticTemporaryUpperCase(); + latinKeyboard.setAutomaticTemporaryUpperCase(); + } else { + final boolean shifted = (shiftMode == MANUAL_SHIFT); // On non-distinct multi touch panel device, we should also turn off the shift locked // state when shift key is pressed to go to normal mode. - // On the other hand, on distinct multi touch panel device, turning off the shift locked - // state with shift key pressing is handled by onReleaseShift(). + // On the other hand, on distinct multi touch panel device, turning off the shift + // locked state with shift key pressing is handled by onReleaseShift(). if (!hasDistinctMultitouch() && !shifted && latinKeyboard.isShiftLocked()) { + mState.setShiftLocked(false); latinKeyboard.setShiftLocked(false); } - if (latinKeyboard.setShifted(shifted)) { - mKeyboardView.invalidateAllKeys(); - } + mState.setShifted(shifted); + latinKeyboard.setShifted(shifted); } + mKeyboardView.invalidateAllKeys(); } private void setShiftLocked(boolean shiftLocked) { LatinKeyboard latinKeyboard = getLatinKeyboard(); - if (latinKeyboard != null && latinKeyboard.setShiftLocked(shiftLocked)) { - mKeyboardView.invalidateAllKeys(); - } + if (latinKeyboard == null) + return; + mState.setShiftLocked(shiftLocked); + latinKeyboard.setShiftLocked(shiftLocked); + mKeyboardView.invalidateAllKeys(); } /** @@ -442,145 +418,135 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha */ public void toggleShift() { mInputMethodService.mHandler.cancelUpdateShiftState(); - if (DEBUG_STATE) - Log.d(TAG, "toggleShift:" - + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() - + " shiftKeyState=" + mShiftKeyState); + if (DEBUG_STATE) { + Log.d(TAG, "toggleShift: " + mState); + } if (isAlphabetMode()) { - setManualTemporaryUpperCase(!isShiftedOrShiftLocked()); + setShifted(mState.isShiftedOrShiftLocked() ? UNSHIFT : MANUAL_SHIFT); } else { - toggleShiftInSymbol(); + toggleShiftInSymbols(); } } public void toggleCapsLock() { mInputMethodService.mHandler.cancelUpdateShiftState(); - if (DEBUG_STATE) - Log.d(TAG, "toggleCapsLock:" - + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() - + " shiftKeyState=" + mShiftKeyState); + if (DEBUG_STATE) { + Log.d(TAG, "toggleCapsLock: " + mState); + } if (isAlphabetMode()) { - if (isShiftLocked()) { + if (mState.isShiftLocked()) { // Shift key is long pressed while caps lock state, we will toggle back to normal // state. And mark as if shift key is released. setShiftLocked(false); - mShiftKeyState.onRelease(); + mState.onToggleCapsLock(); } else { setShiftLocked(true); } } } - private void setAutomaticTemporaryUpperCase() { - if (mKeyboardView == null) return; - final Keyboard keyboard = mKeyboardView.getKeyboard(); - if (keyboard == null) return; - keyboard.setAutomaticTemporaryUpperCase(); - mKeyboardView.invalidateAllKeys(); + public void toggleKeyboardMode() { + if (DEBUG_STATE) { + Log.d(TAG, "toggleKeyboard: " + mState); + } + toggleAlphabetAndSymbols(); + } + + private void startIgnoringDoubleTap() { + if (mKeyboardView != null) { + mKeyboardView.startIgnoringDoubleTap(); + } } /** * Update keyboard shift state triggered by connected EditText status change. */ public void updateShiftState() { - final ShiftKeyState shiftKeyState = mShiftKeyState; - if (DEBUG_STATE) - Log.d(TAG, "updateShiftState:" - + " autoCaps=" + mInputMethodService.getCurrentAutoCapsState() - + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() - + " shiftKeyState=" + shiftKeyState - + " isAlphabetMode=" + isAlphabetMode() - + " isShiftLocked=" + isShiftLocked()); - if (isAlphabetMode()) { - if (!isShiftLocked() && !shiftKeyState.isIgnoring()) { - if (shiftKeyState.isReleasing() && mInputMethodService.getCurrentAutoCapsState()) { + if (DEBUG_STATE) { + Log.d(TAG, "updateShiftState: " + mState + + " autoCaps=" + mInputMethodService.getCurrentAutoCapsState()); + } + final boolean isAlphabetMode = isAlphabetMode(); + final boolean isShiftLocked = mState.isShiftLocked(); + if (isAlphabetMode) { + if (!isShiftLocked && !mState.isShiftKeyIgnoring()) { + if (mState.isShiftKeyReleasing() && mInputMethodService.getCurrentAutoCapsState()) { // Only when shift key is releasing, automatic temporary upper case will be set. - setAutomaticTemporaryUpperCase(); + setShifted(AUTOMATIC_SHIFT); } else { - setManualTemporaryUpperCase(shiftKeyState.isMomentary()); + setShifted(mState.isShiftKeyMomentary() ? MANUAL_SHIFT : UNSHIFT); } } - } else { - // In symbol keyboard mode, we should clear shift key state because only alphabet - // keyboard has shift key. - shiftKeyState.onRelease(); } - } - - public void changeKeyboardMode() { - if (DEBUG_STATE) - Log.d(TAG, "changeKeyboardMode:" - + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() - + " shiftKeyState=" + mShiftKeyState); - toggleKeyboardMode(); - if (isShiftLocked() && isAlphabetMode()) - setShiftLocked(true); - updateShiftState(); + mState.onUpdateShiftState(isAlphabetMode); } public void onPressShift(boolean withSliding) { if (!isKeyboardAvailable()) return; - ShiftKeyState shiftKeyState = mShiftKeyState; - if (DEBUG_STATE) - Log.d(TAG, "onPressShift:" - + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() - + " shiftKeyState=" + shiftKeyState + " sliding=" + withSliding); - if (isAlphabetMode()) { - if (isShiftLocked()) { + if (DEBUG_STATE) { + Log.d(TAG, "onPressShift: " + mState + " sliding=" + withSliding); + } + final boolean isAlphabetMode = isAlphabetMode(); + final boolean isShiftLocked = mState.isShiftLocked(); + final boolean isAutomaticTemporaryUpperCase = mState.isAutomaticTemporaryUpperCase(); + final boolean isShiftedOrShiftLocked = mState.isShiftedOrShiftLocked(); + if (isAlphabetMode) { + if (isShiftLocked) { // Shift key is pressed while caps lock state, we will treat this state as shifted // caps lock state and mark as if shift key pressed while normal state. - shiftKeyState.onPress(); - setManualTemporaryUpperCase(true); - } else if (isAutomaticTemporaryUpperCase()) { + setShifted(MANUAL_SHIFT); + } else if (isAutomaticTemporaryUpperCase) { // Shift key is pressed while automatic temporary upper case, we have to move to // manual temporary upper case. - shiftKeyState.onPress(); - setManualTemporaryUpperCase(true); - } else if (isShiftedOrShiftLocked()) { + setShifted(MANUAL_SHIFT); + } else if (isShiftedOrShiftLocked) { // In manual upper case state, we just record shift key has been pressing while // shifted state. - shiftKeyState.onPressOnShifted(); } else { // In base layout, chording or manual temporary upper case mode is started. - shiftKeyState.onPress(); toggleShift(); } } else { // In symbol mode, just toggle symbol and symbol more keyboard. - shiftKeyState.onPress(); - toggleShift(); + toggleShiftInSymbols(); mSwitchState = SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE; } + mState.onPressShift(isAlphabetMode, isShiftLocked, isAutomaticTemporaryUpperCase, + isShiftedOrShiftLocked); } public void onReleaseShift(boolean withSliding) { if (!isKeyboardAvailable()) return; - ShiftKeyState shiftKeyState = mShiftKeyState; - if (DEBUG_STATE) - Log.d(TAG, "onReleaseShift:" - + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() - + " shiftKeyState=" + shiftKeyState + " sliding=" + withSliding); - if (isAlphabetMode()) { - if (shiftKeyState.isMomentary()) { + if (DEBUG_STATE) { + Log.d(TAG, "onReleaseShift: " + mState + " sliding=" + withSliding); + } + final boolean isAlphabetMode = isAlphabetMode(); + final boolean isShiftLocked = mState.isShiftLocked(); + final boolean isShiftLockShifted = mState.isShiftLockShifted(); + final boolean isShiftedOrShiftLocked = mState.isShiftedOrShiftLocked(); + final boolean isManualTemporaryUpperCaseFromAuto = + mState.isManualTemporaryUpperCaseFromAuto(); + if (isAlphabetMode) { + if (mState.isShiftKeyMomentary()) { // After chording input while normal state. toggleShift(); - } else if (isShiftLocked() && !isShiftLockShifted() && shiftKeyState.isPressing() - && !withSliding) { + } else if (isShiftLocked && !isShiftLockShifted && (mState.isShiftKeyPressing() + || mState.isShiftKeyPressingOnShifted()) && !withSliding) { // Shift has been long pressed, ignore this release. - } else if (isShiftLocked() && !shiftKeyState.isIgnoring() && !withSliding) { + } else if (isShiftLocked && !mState.isShiftKeyIgnoring() && !withSliding) { // Shift has been pressed without chording while caps lock state. toggleCapsLock(); // To be able to turn off caps lock by "double tap" on shift key, we should ignore // the second tap of the "double tap" from now for a while because we just have // already turned off caps lock above. - mKeyboardView.startIgnoringDoubleTap(); - } else if (isShiftedOrShiftLocked() && shiftKeyState.isPressingOnShifted() + startIgnoringDoubleTap(); + } else if (isShiftedOrShiftLocked && mState.isShiftKeyPressingOnShifted() && !withSliding) { // Shift has been pressed without chording while shifted state. toggleShift(); - } else if (isManualTemporaryUpperCaseFromAuto() && shiftKeyState.isPressing() + } else if (isManualTemporaryUpperCaseFromAuto && mState.isShiftKeyPressing() && !withSliding) { // Shift has been pressed without chording while manual temporary upper case // transited from automatic temporary upper case. @@ -590,67 +556,86 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha // In symbol mode, snap back to the previous keyboard mode if the user chords the shift // key and another key, then releases the shift key. if (mSwitchState == SWITCH_STATE_CHORDING_SYMBOL) { - toggleShift(); + toggleShiftInSymbols(); } } - shiftKeyState.onRelease(); + mState.onReleaseShift(); } public void onPressSymbol() { - if (DEBUG_STATE) - Log.d(TAG, "onPressSymbol:" - + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() - + " symbolKeyState=" + mSymbolKeyState); - changeKeyboardMode(); - mSymbolKeyState.onPress(); + if (DEBUG_STATE) { + Log.d(TAG, "onPressSymbol: " + mState); + } + toggleAlphabetAndSymbols(); + mState.onPressSymbol(); mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL; } public void onReleaseSymbol() { - if (DEBUG_STATE) - Log.d(TAG, "onReleaseSymbol:" - + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() - + " symbolKeyState=" + mSymbolKeyState); + if (DEBUG_STATE) { + Log.d(TAG, "onReleaseSymbol: " + mState); + } // Snap back to the previous keyboard mode if the user chords the mode change key and // another key, then releases the mode change key. if (mSwitchState == SWITCH_STATE_CHORDING_ALPHA) { - changeKeyboardMode(); + toggleAlphabetAndSymbols(); } - mSymbolKeyState.onRelease(); + mState.onReleaseSymbol(); } public void onOtherKeyPressed() { - if (DEBUG_STATE) - Log.d(TAG, "onOtherKeyPressed:" - + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() - + " shiftKeyState=" + mShiftKeyState - + " symbolKeyState=" + mSymbolKeyState); - mShiftKeyState.onOtherKeyPressed(); - mSymbolKeyState.onOtherKeyPressed(); + if (DEBUG_STATE) { + Log.d(TAG, "onOtherKeyPressed: " + mState); + } + mState.onOtherKeyPressed(); } public void onCancelInput() { // Snap back to the previous keyboard mode if the user cancels sliding input. - if (getPointerCount() == 1) { + if (isSinglePointer()) { if (mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL) { - changeKeyboardMode(); + toggleAlphabetAndSymbols(); } else if (mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE) { - toggleShift(); + toggleShiftInSymbols(); } } } - private void toggleShiftInSymbol() { - if (isAlphabetMode()) - return; - final LatinKeyboard keyboard; - if (mCurrentId.equals(mSymbolsKeyboardId) - || !mCurrentId.equals(mSymbolsShiftedKeyboardId)) { - keyboard = getKeyboard(mSymbolsShiftedKeyboardId); + private boolean mPrevMainKeyboardWasShiftLocked; + + private void setSymbolsKeyboard() { + mPrevMainKeyboardWasShiftLocked = mState.isShiftLocked(); + setKeyboard(getKeyboard(mSymbolsKeyboardId)); + } + + private void setAlphabetKeyboard() { + setKeyboard(getKeyboard(mMainKeyboardId)); + setShiftLocked(mPrevMainKeyboardWasShiftLocked); + mPrevMainKeyboardWasShiftLocked = false; + } + + private void toggleAlphabetAndSymbols() { + if (isAlphabetMode()) { + setSymbolsKeyboard(); + } else { + setAlphabetKeyboard(); + } + } + + private boolean isSymbolShifted() { + return mCurrentId != null && mCurrentId.equals(mSymbolsShiftedKeyboardId); + } + + private void setSymbolsShiftedKeyboard() { + setKeyboard(getKeyboard(mSymbolsShiftedKeyboardId)); + } + + private void toggleShiftInSymbols() { + if (isSymbolShifted()) { + setSymbolsKeyboard(); } else { - keyboard = getKeyboard(mSymbolsKeyboardId); + setSymbolsShiftedKeyboard(); } - setKeyboard(keyboard); } public boolean isInMomentarySwitchState() { @@ -662,16 +647,8 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha return mKeyboardView != null && !mKeyboardView.isInSlidingKeyInput(); } - private int getPointerCount() { - return mKeyboardView == null ? 0 : mKeyboardView.getPointerCount(); - } - - private void toggleKeyboardMode() { - if (mCurrentId.equals(mMainKeyboardId)) { - setKeyboard(getKeyboard(mSymbolsKeyboardId)); - } else { - setKeyboard(getKeyboard(mMainKeyboardId)); - } + private boolean isSinglePointer() { + return mKeyboardView != null && mKeyboardView.getPointerCount() == 1; } public boolean hasDistinctMultitouch() { @@ -682,7 +659,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha return c == Keyboard.CODE_SPACE || c == Keyboard.CODE_ENTER; } - private static boolean isLayoutSwitchBackCharacter(int c) { + private boolean isLayoutSwitchBackCharacter(int c) { if (TextUtils.isEmpty(mLayoutSwitchBackSymbols)) return false; if (mLayoutSwitchBackSymbols.indexOf(c) >= 0) return true; return false; @@ -692,9 +669,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha * Updates state machine to figure out when to automatically snap back to the previous mode. */ public void onKey(int code) { - if (DEBUG_STATE) + if (DEBUG_STATE) { Log.d(TAG, "onKey: code=" + code + " switchState=" + mSwitchState - + " pointers=" + getPointerCount()); + + " isSinglePointer=" + isSinglePointer()); + } switch (mSwitchState) { case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL: // Only distinct multi touch devices can be in this state. @@ -710,12 +688,12 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } else { mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; } - } else if (getPointerCount() == 1) { + } else if (isSinglePointer()) { // Snap back to the previous keyboard mode if the user pressed the mode change key // and slid to other key, then released the finger. // If the user cancels the sliding input, snapping back to the previous keyboard // mode is handled by {@link #onCancelInput}. - changeKeyboardMode(); + toggleAlphabetAndSymbols(); } else { // Chording input is being started. The keyboard mode will be snapped back to the // previous mode in {@link onReleaseSymbol} when the mode change key is released. @@ -726,10 +704,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha if (code == Keyboard.CODE_SHIFT) { // Detected only the shift key has been pressed on symbol layout, and then released. mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; - } else if (getPointerCount() == 1) { + } else if (isSinglePointer()) { // Snap back to the previous keyboard mode if the user pressed the shift key on // symbol mode and slid to other key, then released the finger. - toggleShift(); + toggleShiftInSymbols(); mSwitchState = SWITCH_STATE_SYMBOL; } else { // Chording input is being started. The keyboard mode will be snapped back to the @@ -743,7 +721,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } // Snap back to alpha keyboard mode immediately if user types a quote character. if (isLayoutSwitchBackCharacter(code)) { - changeKeyboardMode(); + setAlphabetKeyboard(); } break; case SWITCH_STATE_SYMBOL: @@ -751,7 +729,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha // Snap back to alpha keyboard mode if user types one or more non-space/enter // characters followed by a space/enter or a quote character. if (isSpaceCharacter(code) || isLayoutSwitchBackCharacter(code)) { - changeKeyboardMode(); + setAlphabetKeyboard(); } break; } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index 04e672590..d2741edec 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -148,7 +148,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { final PointerTracker tracker = (PointerTracker) msg.obj; switch (msg.what) { case MSG_SHOW_KEY_PREVIEW: - keyboardView.showKey(msg.arg1, tracker); + keyboardView.showKey(tracker); break; case MSG_DISMISS_KEY_PREVIEW: tracker.getKeyPreviewText().setVisibility(View.INVISIBLE); @@ -156,16 +156,15 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } } - public void showKeyPreview(long delay, int keyIndex, PointerTracker tracker) { + public void showKeyPreview(long delay, PointerTracker tracker) { removeMessages(MSG_SHOW_KEY_PREVIEW); final KeyboardView keyboardView = getOuterInstance(); if (keyboardView == null) return; if (tracker.getKeyPreviewText().getVisibility() == VISIBLE || delay == 0) { // Show right away, if it's already visible and finger is moving around - keyboardView.showKey(keyIndex, tracker); + keyboardView.showKey(tracker); } else { - sendMessageDelayed( - obtainMessage(MSG_SHOW_KEY_PREVIEW, keyIndex, 0, tracker), delay); + sendMessageDelayed(obtainMessage(MSG_SHOW_KEY_PREVIEW, tracker), delay); } } @@ -830,9 +829,9 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } @Override - public void showKeyPreview(int keyIndex, PointerTracker tracker) { + public void showKeyPreview(PointerTracker tracker) { if (mShowKeyPreviewPopup) { - mDrawingHandler.showKeyPreview(mDelayBeforePreview, keyIndex, tracker); + mDrawingHandler.showKeyPreview(mDelayBeforePreview, tracker); } } @@ -858,7 +857,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { keyPreview, FrameLayoutCompatUtils.newLayoutParam(mPreviewPlacer, 0, 0)); } - private void showKey(final int keyIndex, PointerTracker tracker) { + private void showKey(PointerTracker tracker) { final TextView previewText = tracker.getKeyPreviewText(); // If the key preview has no parent view yet, add it to the ViewGroup which can place // key preview absolutely in SoftInputWindow. @@ -867,8 +866,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } mDrawingHandler.cancelDismissKeyPreview(tracker); - final Key key = tracker.getKey(keyIndex); - // If keyIndex is invalid or IME is already closed, we must not show key preview. + final Key key = tracker.getKey(); + // If key is invalid or IME is already closed, we must not show key preview. // Trying to show key preview while root window is closed causes // WindowManager.BadTokenException. if (key == null) @@ -906,12 +905,16 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { int previewX = keyDrawX - (previewWidth - keyDrawWidth) / 2 + params.mCoordinates[0]; final int previewY = key.mY - previewHeight + params.mCoordinates[1] + params.mPreviewOffset; - if (previewX < 0 && params.mPreviewLeftBackground != null) { - previewText.setBackgroundDrawable(params.mPreviewLeftBackground); + if (previewX < 0) { previewX = 0; - } else if (previewX + previewWidth > getWidth() && params.mPreviewRightBackground != null) { - previewText.setBackgroundDrawable(params.mPreviewRightBackground); + if (params.mPreviewLeftBackground != null) { + previewText.setBackgroundDrawable(params.mPreviewLeftBackground); + } + } else if (previewX > getWidth() - previewWidth) { previewX = getWidth() - previewWidth; + if (params.mPreviewRightBackground != null) { + previewText.setBackgroundDrawable(params.mPreviewRightBackground); + } } // Set the preview background state diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java index 762039625..a9fcd9ac4 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java @@ -176,7 +176,7 @@ public class LatinKeyboard extends Keyboard { @Override public CharSequence adjustLabelCase(CharSequence label) { - if (isAlphaKeyboard() && isShiftedOrShiftLocked() && !TextUtils.isEmpty(label) + if (mId.isAlphabetKeyboard() && isShiftedOrShiftLocked() && !TextUtils.isEmpty(label) && label.length() < 3 && Character.isLowerCase(label.charAt(0))) { return label.toString().toUpperCase(mId.mLocale); } diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index 6ce3876b6..af5f808fd 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -21,7 +21,6 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Canvas; import android.os.Message; -import android.os.SystemClock; import android.util.AttributeSet; import android.util.Log; import android.view.GestureDetector; @@ -75,7 +74,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke private final boolean mHasDistinctMultitouch; private int mOldPointerCount = 1; - private int mOldKeyIndex; + private Key mOldKey; private final boolean mConfigShowMiniKeyboardAtTouchedPoint; protected KeyDetector mKeyDetector; @@ -90,6 +89,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke private static final int MSG_REPEAT_KEY = 1; private static final int MSG_LONGPRESS_KEY = 2; private static final int MSG_IGNORE_DOUBLE_TAP = 3; + private static final int MSG_KEY_TYPED = 4; private boolean mInKeyRepeat; @@ -103,19 +103,19 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke final PointerTracker tracker = (PointerTracker) msg.obj; switch (msg.what) { case MSG_REPEAT_KEY: - tracker.onRepeatKey(msg.arg1); - startKeyRepeatTimer(keyboardView.mKeyRepeatInterval, msg.arg1, tracker); + tracker.onRepeatKey(tracker.getKey()); + startKeyRepeatTimer(keyboardView.mKeyRepeatInterval, tracker); break; case MSG_LONGPRESS_KEY: - keyboardView.openMiniKeyboardIfRequired(msg.arg1, tracker); + keyboardView.openMiniKeyboardIfRequired(tracker.getKey(), tracker); break; } } @Override - public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker) { + public void startKeyRepeatTimer(long delay, PointerTracker tracker) { mInKeyRepeat = true; - sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, keyIndex, 0, tracker), delay); + sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, tracker), delay); } public void cancelKeyRepeatTimer() { @@ -128,9 +128,9 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke } @Override - public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker) { + public void startLongPressTimer(long delay, PointerTracker tracker) { cancelLongPressTimer(); - sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, keyIndex, 0, tracker), delay); + sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, tracker), delay); } @Override @@ -139,6 +139,17 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke } @Override + public void startKeyTypedTimer(long delay) { + removeMessages(MSG_KEY_TYPED); + sendMessageDelayed(obtainMessage(MSG_KEY_TYPED), delay); + } + + @Override + public boolean isTyping() { + return hasMessages(MSG_KEY_TYPED); + } + + @Override public void cancelKeyTimers() { cancelKeyRepeatTimer(); cancelLongPressTimer(); @@ -166,12 +177,13 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke public boolean onDoubleTap(MotionEvent firstDown) { final Keyboard keyboard = getKeyboard(); if (ENABLE_CAPSLOCK_BY_DOUBLETAP && keyboard instanceof LatinKeyboard - && ((LatinKeyboard) keyboard).isAlphaKeyboard()) { + && ((LatinKeyboard) keyboard).mId.isAlphabetKeyboard()) { final int pointerIndex = firstDown.getActionIndex(); final int id = firstDown.getPointerId(pointerIndex); final PointerTracker tracker = getPointerTracker(id); + final Key key = tracker.getKeyOn((int)firstDown.getX(), (int)firstDown.getY()); // If the first down event is on shift key. - if (tracker.isOnShiftKey((int) firstDown.getX(), (int) firstDown.getY())) { + if (key != null && key.isShift()) { mProcessingShiftDoubleTapEvent = true; return true; } @@ -188,8 +200,9 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke final int pointerIndex = secondDown.getActionIndex(); final int id = secondDown.getPointerId(pointerIndex); final PointerTracker tracker = getPointerTracker(id); + final Key key = tracker.getKeyOn((int)secondDown.getX(), (int)secondDown.getY()); // If the second down event is also on shift key. - if (tracker.isOnShiftKey((int) secondDown.getX(), (int) secondDown.getY())) { + if (key != null && key.isShift()) { // Detected a double tap on shift key. If we are in the ignoring double tap // mode, it means we have already turned off caps lock in // {@link KeyboardSwitcher#onReleaseShift} . @@ -264,20 +277,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke return mKeyTimerHandler; } - @Override - public void setKeyPreviewPopupEnabled(boolean previewEnabled, int delay) { - final Keyboard keyboard = getKeyboard(); - if (keyboard instanceof LatinKeyboard) { - final LatinKeyboard latinKeyboard = (LatinKeyboard)keyboard; - if (latinKeyboard.isPhoneKeyboard() || latinKeyboard.isNumberKeyboard()) { - // Phone and number keyboard never shows popup preview. - super.setKeyPreviewPopupEnabled(false, delay); - return; - } - } - super.setKeyPreviewPopupEnabled(previewEnabled, delay); - } - /** * Attaches a keyboard to this view. The keyboard can be switched at any time and the * view will re-layout itself to accommodate the keyboard. @@ -329,7 +328,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke super.cancelAllMessages(); } - private boolean openMiniKeyboardIfRequired(int keyIndex, PointerTracker tracker) { + private boolean openMiniKeyboardIfRequired(Key parentKey, PointerTracker tracker) { // Check if we have a popup layout specified first. if (mMoreKeysLayout == 0) { return false; @@ -338,7 +337,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke // Check if we are already displaying popup panel. if (mMoreKeysPanel != null) return false; - final Key parentKey = tracker.getKey(keyIndex); if (parentKey == null) return false; return onLongPress(parentKey, tracker); @@ -349,9 +347,11 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke // When shift key is double tapped, the first tap is correctly processed as usual tap. And // the second tap is treated as this double tap event, so that we need not mark tracker // calling setAlreadyProcessed() nor remove the tracker from mPointerQueue. - final int primaryCode = ignore ? Keyboard.CODE_HAPTIC_AND_AUDIO_FEEDBACK_ONLY - : Keyboard.CODE_CAPSLOCK; - invokeCodeInput(primaryCode); + if (ignore) { + mKeyboardActionListener.onCustomRequest(LatinIME.CODE_HAPTIC_AND_AUDIO_FEEDBACK); + } else { + mKeyboardActionListener.onCodeInput(Keyboard.CODE_CAPSLOCK, null, 0, 0); + } } // This default implementation returns a more keys panel. @@ -396,14 +396,14 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke final Keyboard keyboard = getKeyboard(); if (keyboard instanceof LatinKeyboard) { final LatinKeyboard latinKeyboard = (LatinKeyboard) keyboard; - if (primaryCode == Keyboard.CODE_DIGIT0 && latinKeyboard.isPhoneKeyboard()) { + if (primaryCode == Keyboard.CODE_DIGIT0 && latinKeyboard.mId.isPhoneKeyboard()) { tracker.onLongPressed(); // Long pressing on 0 in phone number keypad gives you a '+'. invokeCodeInput(Keyboard.CODE_PLUS); invokeReleaseKey(primaryCode); return true; } - if (primaryCode == Keyboard.CODE_SHIFT && latinKeyboard.isAlphaKeyboard()) { + if (primaryCode == Keyboard.CODE_SHIFT && latinKeyboard.mId.isAlphabetKeyboard()) { tracker.onLongPressed(); invokeCodeInput(Keyboard.CODE_CAPSLOCK); invokeReleaseKey(primaryCode); @@ -463,8 +463,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke this, this, pointX, pointY, mMoreKeysWindow, getKeyboardActionListener()); final int translatedX = moreKeysPanel.translateX(tracker.getLastX()); final int translatedY = moreKeysPanel.translateY(tracker.getLastY()); - tracker.onShowMoreKeysPanel( - translatedX, translatedY, SystemClock.uptimeMillis(), moreKeysPanel); + tracker.onShowMoreKeysPanel(translatedX, translatedY, moreKeysPanel); dimEntireKeyboard(true); return true; } @@ -548,8 +547,8 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke // Multi-touch to single touch transition. // Send a down event for the latest pointer if the key is different from the // previous key. - final int newKeyIndex = tracker.getKeyIndexOn(x, y); - if (mOldKeyIndex != newKeyIndex) { + final Key newKey = tracker.getKeyOn(x, y); + if (mOldKey != newKey) { tracker.onDownEvent(x, y, eventTime, this); if (action == MotionEvent.ACTION_UP) tracker.onUpEvent(x, y, eventTime); @@ -559,7 +558,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke // Send an up event for the last pointer. final int lastX = tracker.getLastX(); final int lastY = tracker.getLastY(); - mOldKeyIndex = tracker.getKeyIndexOn(lastX, lastY); + mOldKey = tracker.getKeyOn(lastX, lastY); tracker.onUpEvent(lastX, lastY, eventTime); } else if (pointerCount == 1 && oldPointerCount == 1) { tracker.processMotionEvent(action, x, y, eventTime, this); diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java index f2c5b7b49..8e9929681 100644 --- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java @@ -132,9 +132,8 @@ public class MiniKeyboardView extends KeyboardView implements MoreKeysPanel { @Override public void setShifted(boolean shifted) { final Keyboard keyboard = getKeyboard(); - if (keyboard.setShifted(shifted)) { - invalidateAllKeys(); - } + keyboard.setShifted(shifted); + invalidateAllKeys(); } @Override diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java index d20204611..742ee98d7 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysDetector.java @@ -16,8 +16,6 @@ package com.android.inputmethod.keyboard; -import java.util.List; - public class MoreKeysDetector extends KeyDetector { private final int mSlideAllowanceSquare; private final int mSlideAllowanceSquareTop; @@ -41,24 +39,23 @@ public class MoreKeysDetector extends KeyDetector { } @Override - public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) { - final List<Key> keys = getKeyboard().mKeys; + public Key getKeyAndNearbyCodes(int x, int y, final int[] allCodes) { final int touchX = getTouchX(x); final int touchY = getTouchY(y); - int nearestIndex = NOT_A_KEY; + Key nearestKey = null; int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare; - final int keyCount = keys.size(); - for (int index = 0; index < keyCount; index++) { - final int dist = keys.get(index).squaredDistanceToEdge(touchX, touchY); + for (final Key key : getKeyboard().mKeys) { + final int dist = key.squaredDistanceToEdge(touchX, touchY); if (dist < nearestDist) { - nearestIndex = index; + nearestKey = key; nearestDist = dist; } } - if (allCodes != null && nearestIndex != NOT_A_KEY) - allCodes[0] = keys.get(nearestIndex).mCode; - return nearestIndex; + if (allCodes != null && nearestKey != null) { + allCodes[0] = nearestKey.mCode; + } + return nearestKey; } -}
\ No newline at end of file +} diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java b/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java index 6314a99db..a3ff37269 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java @@ -24,6 +24,7 @@ public interface MoreKeysPanel extends PointerTracker.KeyEventHandler { public boolean dismissMoreKeysPanel(); } + // TODO: Remove this method. public void setShifted(boolean shifted); /** diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 198e06aab..9e0c5ce02 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -18,6 +18,7 @@ package com.android.inputmethod.keyboard; import android.content.Context; import android.content.res.Resources; +import android.os.SystemClock; import android.util.Log; import android.view.MotionEvent; import android.widget.TextView; @@ -27,7 +28,6 @@ import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; public class PointerTracker { @@ -67,22 +67,28 @@ public class PointerTracker { public interface DrawingProxy extends MoreKeysPanel.Controller { public void invalidateKey(Key key); public TextView inflateKeyPreviewText(); - public void showKeyPreview(int keyIndex, PointerTracker tracker); + public void showKeyPreview(PointerTracker tracker); public void cancelShowKeyPreview(PointerTracker tracker); public void dismissKeyPreview(PointerTracker tracker); } public interface TimerProxy { - public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker); - public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker); + public void startKeyTypedTimer(long delay); + public boolean isTyping(); + public void startKeyRepeatTimer(long delay, PointerTracker tracker); + public void startLongPressTimer(long delay, PointerTracker tracker); public void cancelLongPressTimer(); public void cancelKeyTimers(); public static class Adapter implements TimerProxy { @Override - public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker) {} + public void startKeyTypedTimer(long delay) {} @Override - public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker) {} + public boolean isTyping() { return false; } + @Override + public void startKeyRepeatTimer(long delay, PointerTracker tracker) {} + @Override + public void startLongPressTimer(long delay, PointerTracker tracker) {} @Override public void cancelLongPressTimer() {} @Override @@ -97,6 +103,7 @@ public class PointerTracker { private static int sLongPressKeyTimeout; private static int sLongPressShiftKeyTimeout; private static int sLongPressSpaceKeyTimeout; + private static int sIgnoreSpecialKeyTimeout; private static int sTouchNoiseThresholdMillis; private static int sTouchNoiseThresholdDistanceSquared; @@ -119,9 +126,9 @@ public class PointerTracker { private long mDownTime; private long mUpTime; - // The current key index where this pointer is. - private int mKeyIndex = KeyDetector.NOT_A_KEY; - // The position where mKeyIndex was recognized for the first time. + // The current key where this pointer is. + private Key mCurrentKey = null; + // The position where the current key was recognized for the first time. private int mKeyX; private int mKeyY; @@ -167,7 +174,9 @@ public class PointerTracker { sLongPressKeyTimeout = res.getInteger(R.integer.config_long_press_key_timeout); sLongPressShiftKeyTimeout = res.getInteger(R.integer.config_long_press_shift_key_timeout); sLongPressSpaceKeyTimeout = res.getInteger(R.integer.config_long_press_space_key_timeout); + sIgnoreSpecialKeyTimeout = res.getInteger(R.integer.config_ignore_special_key_timeout); sTouchNoiseThresholdMillis = res.getInteger(R.integer.config_touch_noise_threshold_millis); + final float touchNoiseThresholdDistance = res.getDimension( R.dimen.config_touch_noise_threshold_distance); sTouchNoiseThresholdDistanceSquared = (int)( @@ -207,7 +216,7 @@ public class PointerTracker { public static void dismissAllKeyPreviews() { for (final PointerTracker tracker : sTrackers) { - tracker.setReleasedKeyGraphics(tracker.mKeyIndex); + tracker.setReleasedKeyGraphics(tracker.mCurrentKey); } } @@ -228,12 +237,15 @@ public class PointerTracker { // Returns true if keyboard has been changed by this callback. private boolean callListenerOnPressAndCheckKeyboardLayoutChange(Key key, boolean withSliding) { - final boolean ignoreModifierKey = mIgnoreModifierKey && isModifierCode(key.mCode); - if (DEBUG_LISTENER) - Log.d(TAG, "onPress : " + keyCodePrintable(key.mCode) + " sliding=" + withSliding - + " ignoreModifier=" + ignoreModifierKey); - if (ignoreModifierKey) + final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); + if (DEBUG_LISTENER) { + Log.d(TAG, "onPress : " + KeyDetector.printableCode(key.mCode) + + " sliding=" + withSliding + " ignoreModifier=" + ignoreModifierKey + + " enabled=" + key.isEnabled()); + } + if (ignoreModifierKey) { return false; + } if (key.isEnabled()) { mListener.onPress(key.mCode, withSliding); final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged; @@ -246,35 +258,47 @@ public class PointerTracker { // Note that we need primaryCode argument because the keyboard may in shifted state and the // primaryCode is different from {@link Key#mCode}. private void callListenerOnCodeInput(Key key, int primaryCode, int[] keyCodes, int x, int y) { - final boolean ignoreModifierKey = mIgnoreModifierKey && isModifierCode(key.mCode); - if (DEBUG_LISTENER) - Log.d(TAG, "onCodeInput: " + keyCodePrintable(primaryCode) - + " codes="+ Arrays.toString(keyCodes) + " x=" + x + " y=" + y - + " ignoreModifier=" + ignoreModifierKey); - if (ignoreModifierKey) + final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); + final boolean alterCode = key.altCodeWhileTyping() && mTimerProxy.isTyping(); + final int code = alterCode ? key.mAltCode : primaryCode; + // If code is CODE_DUMMY here, this key will be ignored or generate text. + final CharSequence text = (code != Keyboard.CODE_DUMMY) ? null : key.mOutputText; + if (DEBUG_LISTENER) { + Log.d(TAG, "onCodeInput: " + KeyDetector.printableCode(code) + " text=" + text + + " codes="+ KeyDetector.printableCodes(keyCodes) + " x=" + x + " y=" + y + + " ignoreModifier=" + ignoreModifierKey + " alterCode=" + alterCode + + " enabled=" + key.isEnabled()); + } + if (ignoreModifierKey) { return; - if (key.isEnabled()) - mListener.onCodeInput(primaryCode, keyCodes, x, y); - } - - private void callListenerOnTextInput(Key key) { - if (DEBUG_LISTENER) - Log.d(TAG, "onTextInput: text=" + key.mOutputText); - if (key.isEnabled()) - mListener.onTextInput(key.mOutputText); + } + if (key.isEnabled()) { + if (code != Keyboard.CODE_DUMMY) { + mListener.onCodeInput(code, keyCodes, x, y); + } else if (text != null) { + mListener.onTextInput(text); + } + if (!key.altCodeWhileTyping() && !key.isModifier()) { + mTimerProxy.startKeyTypedTimer(sIgnoreSpecialKeyTimeout); + } + } } // Note that we need primaryCode argument because the keyboard may in shifted state and the // primaryCode is different from {@link Key#mCode}. private void callListenerOnRelease(Key key, int primaryCode, boolean withSliding) { - final boolean ignoreModifierKey = mIgnoreModifierKey && isModifierCode(key.mCode); - if (DEBUG_LISTENER) - Log.d(TAG, "onRelease : " + keyCodePrintable(primaryCode) + " sliding=" - + withSliding + " ignoreModifier=" + ignoreModifierKey); - if (ignoreModifierKey) + final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); + if (DEBUG_LISTENER) { + Log.d(TAG, "onRelease : " + KeyDetector.printableCode(primaryCode) + + " sliding=" + withSliding + " ignoreModifier=" + ignoreModifierKey + + " enabled="+ key.isEnabled()); + } + if (ignoreModifierKey) { return; - if (key.isEnabled()) + } + if (key.isEnabled()) { mListener.onRelease(primaryCode, withSliding); + } } private void callListenerOnCancelInput() { @@ -295,71 +319,69 @@ public class PointerTracker { return mIsInSlidingKeyInput; } - private boolean isValidKeyIndex(int keyIndex) { - return keyIndex >= 0 && keyIndex < mKeys.size(); - } - - public Key getKey(int keyIndex) { - return isValidKeyIndex(keyIndex) ? mKeys.get(keyIndex) : null; - } - - private static boolean isModifierCode(int primaryCode) { - return primaryCode == Keyboard.CODE_SHIFT - || primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL; - } - - private boolean isModifierInternal(int keyIndex) { - final Key key = getKey(keyIndex); - return key == null ? false : isModifierCode(key.mCode); + public Key getKey() { + return mCurrentKey; } public boolean isModifier() { - return isModifierInternal(mKeyIndex); - } - - private boolean isOnModifierKey(int x, int y) { - return isModifierInternal(mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null)); - } - - public boolean isOnShiftKey(int x, int y) { - final Key key = getKey(mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null)); - return key != null && key.mCode == Keyboard.CODE_SHIFT; + return mCurrentKey != null && mCurrentKey.isModifier(); } - public int getKeyIndexOn(int x, int y) { - return mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); + public Key getKeyOn(int x, int y) { + return mKeyDetector.getKeyAndNearbyCodes(x, y, null); } - private void setReleasedKeyGraphics(int keyIndex) { + private void setReleasedKeyGraphics(Key key) { mDrawingProxy.dismissKeyPreview(this); - final Key key = getKey(keyIndex); if (key != null && key.isEnabled()) { key.onReleased(); mDrawingProxy.invalidateKey(key); + + if (key.isShift()) { + for (final Key shiftKey : mKeyboard.mShiftKeys) { + if (shiftKey != key) { + shiftKey.onReleased(); + mDrawingProxy.invalidateKey(shiftKey); + } + } + } + + if (key.altCodeWhileTyping()) { + final Key altKey = mKeyboard.getKey(key.mAltCode); + if (altKey != null) { + altKey.onReleased(); + mDrawingProxy.invalidateKey(altKey); + } + } } } - private void setPressedKeyGraphics(int keyIndex) { - final Key key = getKey(keyIndex); + private void setPressedKeyGraphics(Key key) { if (key != null && key.isEnabled()) { - if (isKeyPreviewRequired(key)) { - mDrawingProxy.showKeyPreview(keyIndex, this); + if (!key.noKeyPreview()) { + mDrawingProxy.showKeyPreview(this); } key.onPressed(); mDrawingProxy.invalidateKey(key); - } - } - // The modifier key, such as shift key, should not show its key preview. - private static boolean isKeyPreviewRequired(Key key) { - final int code = key.mCode; - // TODO: Stop hard-coding these key codes here, and add a new key attribute of a key. - if (code == Keyboard.CODE_SPACE || code == Keyboard.CODE_ENTER - || code == Keyboard.CODE_DELETE || isModifierCode(code) - || code == Keyboard.CODE_SETTINGS || code == Keyboard.CODE_SHORTCUT) { - return false; + if (key.isShift()) { + for (final Key shiftKey : mKeyboard.mShiftKeys) { + if (shiftKey != key) { + shiftKey.onPressed(); + mDrawingProxy.invalidateKey(shiftKey); + } + } + } + + if (key.altCodeWhileTyping() && mTimerProxy.isTyping()) { + final Key altKey = mKeyboard.getKey(key.mAltCode); + if (altKey != null) { + // TODO: Show altKey's preview. + altKey.onPressed(); + mDrawingProxy.invalidateKey(altKey); + } + } } - return true; } public int getLastX() { @@ -374,31 +396,31 @@ public class PointerTracker { return mDownTime; } - private int onDownKey(int x, int y, long eventTime) { + private Key onDownKey(int x, int y, long eventTime) { mDownTime = eventTime; return onMoveToNewKey(onMoveKeyInternal(x, y), x, y); } - private int onMoveKeyInternal(int x, int y) { + private Key onMoveKeyInternal(int x, int y) { mLastX = x; mLastY = y; - return mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); + return mKeyDetector.getKeyAndNearbyCodes(x, y, null); } - private int onMoveKey(int x, int y) { + private Key onMoveKey(int x, int y) { return onMoveKeyInternal(x, y); } - private int onMoveToNewKey(int keyIndex, int x, int y) { - mKeyIndex = keyIndex; + private Key onMoveToNewKey(Key newKey, int x, int y) { + mCurrentKey = newKey; mKeyX = x; mKeyY = y; - return keyIndex; + return newKey; } - private int onUpKey(int x, int y, long eventTime) { + private Key onUpKey(int x, int y, long eventTime) { mUpTime = eventTime; - mKeyIndex = KeyDetector.NOT_A_KEY; + mCurrentKey = null; return onMoveKeyInternal(x, y); } @@ -447,7 +469,8 @@ public class PointerTracker { final PointerTrackerQueue queue = sPointerTrackerQueue; if (queue != null) { - if (isOnModifierKey(x, y)) { + final Key key = getKeyOn(x, y); + if (key != null && key.isModifier()) { // Before processing a down event of modifier key, all pointers already being // tracked should be released. queue.releaseAllPointers(eventTime); @@ -458,32 +481,35 @@ public class PointerTracker { } private void onDownEventInternal(int x, int y, long eventTime) { - int keyIndex = onDownKey(x, y, eventTime); + Key key = onDownKey(x, y, eventTime); // Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding // from modifier key, or 3) this pointer's KeyDetector always allows sliding input. - mIsAllowedSlidingKeyInput = sConfigSlidingKeyInputEnabled || isModifierInternal(keyIndex) + mIsAllowedSlidingKeyInput = sConfigSlidingKeyInputEnabled + || (key != null && key.isModifier()) || mKeyDetector.alwaysAllowsSlidingInput(); mKeyboardLayoutHasBeenChanged = false; mKeyAlreadyProcessed = false; mIsRepeatableKey = false; mIsInSlidingKeyInput = false; mIgnoreModifierKey = false; - if (isValidKeyIndex(keyIndex)) { + if (key != null) { // This onPress call may have changed keyboard layout. Those cases are detected at - // {@link #setKeyboard}. In those cases, we should update keyIndex according to the new + // {@link #setKeyboard}. In those cases, we should update key according to the new // keyboard layout. - if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex), false)) - keyIndex = onDownKey(x, y, eventTime); + if (callListenerOnPressAndCheckKeyboardLayoutChange(key, false)) { + key = onDownKey(x, y, eventTime); + } - startRepeatKey(keyIndex); - startLongPressTimer(keyIndex); - setPressedKeyGraphics(keyIndex); + startRepeatKey(key); + startLongPressTimer(key); + setPressedKeyGraphics(key); } } private void startSlidingKeyInput(Key key) { - if (!mIsInSlidingKeyInput) - mIgnoreModifierKey = isModifierCode(key.mCode); + if (!mIsInSlidingKeyInput) { + mIgnoreModifierKey = key.isModifier(); + } mIsInSlidingKeyInput = true; } @@ -495,39 +521,40 @@ public class PointerTracker { final int lastX = mLastX; final int lastY = mLastY; - final int oldKeyIndex = mKeyIndex; - final Key oldKey = getKey(oldKeyIndex); - int keyIndex = onMoveKey(x, y); - if (isValidKeyIndex(keyIndex)) { + final Key oldKey = mCurrentKey; + Key key = onMoveKey(x, y); + if (key != null) { if (oldKey == null) { // The pointer has been slid in to the new key, but the finger was not on any keys. // In this case, we must call onPress() to notify that the new key is being pressed. // This onPress call may have changed keyboard layout. Those cases are detected at - // {@link #setKeyboard}. In those cases, we should update keyIndex according to the + // {@link #setKeyboard}. In those cases, we should update key according to the // new keyboard layout. - if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex), true)) - keyIndex = onMoveKey(x, y); - onMoveToNewKey(keyIndex, x, y); - startLongPressTimer(keyIndex); - setPressedKeyGraphics(keyIndex); - } else if (isMajorEnoughMoveToBeOnNewKey(x, y, keyIndex)) { + if (callListenerOnPressAndCheckKeyboardLayoutChange(key, true)) { + key = onMoveKey(x, y); + } + onMoveToNewKey(key, x, y); + startLongPressTimer(key); + setPressedKeyGraphics(key); + } else if (isMajorEnoughMoveToBeOnNewKey(x, y, key)) { // The pointer has been slid in to the new key from the previous key, we must call // onRelease() first to notify that the previous key has been released, then call // onPress() to notify that the new key is being pressed. - setReleasedKeyGraphics(oldKeyIndex); + setReleasedKeyGraphics(oldKey); callListenerOnRelease(oldKey, oldKey.mCode, true); startSlidingKeyInput(oldKey); mTimerProxy.cancelKeyTimers(); - startRepeatKey(keyIndex); + startRepeatKey(key); if (mIsAllowedSlidingKeyInput) { // This onPress call may have changed keyboard layout. Those cases are detected - // at {@link #setKeyboard}. In those cases, we should update keyIndex according + // at {@link #setKeyboard}. In those cases, we should update key according // to the new keyboard layout. - if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex), true)) - keyIndex = onMoveKey(x, y); - onMoveToNewKey(keyIndex, x, y); - startLongPressTimer(keyIndex); - setPressedKeyGraphics(keyIndex); + if (callListenerOnPressAndCheckKeyboardLayoutChange(key, true)) { + key = onMoveKey(x, y); + } + onMoveToNewKey(key, x, y); + startLongPressTimer(key); + setPressedKeyGraphics(key); } else { // HACK: On some devices, quick successive touches may be translated to sudden // move by touch panel firmware. This hack detects the case and translates the @@ -543,20 +570,20 @@ public class PointerTracker { onDownEventInternal(x, y, eventTime); } else { mKeyAlreadyProcessed = true; - setReleasedKeyGraphics(oldKeyIndex); + setReleasedKeyGraphics(oldKey); } } } } else { - if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, keyIndex)) { + if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, key)) { // The pointer has been slid out from the previous key, we must call onRelease() to // notify that the previous key has been released. - setReleasedKeyGraphics(oldKeyIndex); + setReleasedKeyGraphics(oldKey); callListenerOnRelease(oldKey, oldKey.mCode, true); startSlidingKeyInput(oldKey); mTimerProxy.cancelLongPressTimer(); if (mIsAllowedSlidingKeyInput) { - onMoveToNewKey(keyIndex, x, y); + onMoveToNewKey(key, x, y); } else { mKeyAlreadyProcessed = true; } @@ -570,7 +597,7 @@ public class PointerTracker { final PointerTrackerQueue queue = sPointerTrackerQueue; if (queue != null) { - if (isModifier()) { + if (mCurrentKey != null && mCurrentKey.isModifier()) { // Before processing an up event of modifier key, all pointers already being // tracked should be released. queue.releaseAllPointersExcept(this, eventTime); @@ -605,8 +632,8 @@ public class PointerTracker { keyX = mKeyX; keyY = mKeyY; } - final int keyIndex = onUpKey(keyX, keyY, eventTime); - setReleasedKeyGraphics(keyIndex); + final Key key = onUpKey(keyX, keyY, eventTime); + setReleasedKeyGraphics(key); if (mIsShowingMoreKeysPanel) { mDrawingProxy.dismissMoreKeysPanel(); mIsShowingMoreKeysPanel = false; @@ -614,19 +641,19 @@ public class PointerTracker { if (mKeyAlreadyProcessed) return; if (!mIsRepeatableKey) { - detectAndSendKey(keyIndex, keyX, keyY); + detectAndSendKey(key, keyX, keyY); } } - public void onShowMoreKeysPanel(int x, int y, long eventTime, KeyEventHandler handler) { + public void onShowMoreKeysPanel(int x, int y, KeyEventHandler handler) { onLongPressed(); - onDownEvent(x, y, eventTime, handler); + onDownEvent(x, y, SystemClock.uptimeMillis(), handler); mIsShowingMoreKeysPanel = true; } public void onLongPressed() { mKeyAlreadyProcessed = true; - setReleasedKeyGraphics(mKeyIndex); + setReleasedKeyGraphics(mCurrentKey); final PointerTrackerQueue queue = sPointerTrackerQueue; if (queue != null) { queue.remove(this); @@ -648,7 +675,7 @@ public class PointerTracker { private void onCancelEventInternal() { mTimerProxy.cancelKeyTimers(); mDrawingProxy.cancelShowKeyPreview(this); - setReleasedKeyGraphics(mKeyIndex); + setReleasedKeyGraphics(mCurrentKey); mIsInSlidingKeyInput = false; if (mIsShowingMoreKeysPanel) { mDrawingProxy.dismissMoreKeysPanel(); @@ -656,48 +683,45 @@ public class PointerTracker { } } - private void startRepeatKey(int keyIndex) { - final Key key = getKey(keyIndex); - if (key != null && key.mRepeatable) { - onRepeatKey(keyIndex); - mTimerProxy.startKeyRepeatTimer(sDelayBeforeKeyRepeatStart, keyIndex, this); + private void startRepeatKey(Key key) { + if (key != null && key.isRepeatable()) { + onRepeatKey(key); + mTimerProxy.startKeyRepeatTimer(sDelayBeforeKeyRepeatStart, this); mIsRepeatableKey = true; } else { mIsRepeatableKey = false; } } - public void onRepeatKey(int keyIndex) { - Key key = getKey(keyIndex); + public void onRepeatKey(Key key) { if (key != null) { - detectAndSendKey(keyIndex, key.mX, key.mY); + detectAndSendKey(key, key.mX, key.mY); } } - private boolean isMajorEnoughMoveToBeOnNewKey(int x, int y, int newKey) { + private boolean isMajorEnoughMoveToBeOnNewKey(int x, int y, Key newKey) { if (mKeys == null || mKeyDetector == null) throw new NullPointerException("keyboard and/or key detector not set"); - int curKey = mKeyIndex; + Key curKey = mCurrentKey; if (newKey == curKey) { return false; - } else if (isValidKeyIndex(curKey)) { - return mKeys.get(curKey).squaredDistanceToEdge(x, y) + } else if (curKey != null) { + return curKey.squaredDistanceToEdge(x, y) >= mKeyDetector.getKeyHysteresisDistanceSquared(); } else { return true; } } - private void startLongPressTimer(int keyIndex) { - Key key = getKey(keyIndex); + private void startLongPressTimer(Key key) { if (key == null) return; if (key.mCode == Keyboard.CODE_SHIFT) { if (sLongPressShiftKeyTimeout > 0) { - mTimerProxy.startLongPressTimer(sLongPressShiftKeyTimeout, keyIndex, this); + mTimerProxy.startLongPressTimer(sLongPressShiftKeyTimeout, this); } } else if (key.mCode == Keyboard.CODE_SPACE) { if (sLongPressSpaceKeyTimeout > 0) { - mTimerProxy.startLongPressTimer(sLongPressSpaceKeyTimeout, keyIndex, this); + mTimerProxy.startLongPressTimer(sLongPressSpaceKeyTimeout, this); } } else if (key.hasUppercaseLetter() && mKeyboard.isManualTemporaryUpperCase()) { // We need not start long press timer on the key which has manual temporary upper case @@ -705,59 +729,48 @@ public class PointerTracker { return; } else if (sKeyboardSwitcher.isInMomentarySwitchState()) { // We use longer timeout for sliding finger input started from the symbols mode key. - mTimerProxy.startLongPressTimer(sLongPressKeyTimeout * 3, keyIndex, this); + mTimerProxy.startLongPressTimer(sLongPressKeyTimeout * 3, this); } else { - mTimerProxy.startLongPressTimer(sLongPressKeyTimeout, keyIndex, this); + mTimerProxy.startLongPressTimer(sLongPressKeyTimeout, this); } } - private void detectAndSendKey(int index, int x, int y) { - final Key key = getKey(index); + private void detectAndSendKey(Key key, int x, int y) { if (key == null) { callListenerOnCancelInput(); return; } - if (key.mOutputText != null) { - callListenerOnTextInput(key); - callListenerOnRelease(key, key.mCode, false); - } else { - int code = key.mCode; - final int[] codes = mKeyDetector.newCodeArray(); - mKeyDetector.getKeyIndexAndNearbyCodes(x, y, codes); - - // If keyboard is in manual temporary upper case state and key has manual temporary - // uppercase letter as key hint letter, alternate character code should be sent. - if (mKeyboard.isManualTemporaryUpperCase() && key.hasUppercaseLetter()) { - code = key.mHintLabel.charAt(0); - codes[0] = code; - } - // Swap the first and second values in the codes array if the primary code is not the - // first value but the second value in the array. This happens when key debouncing is - // in effect. - if (codes.length >= 2 && codes[0] != code && codes[1] == code) { - codes[1] = codes[0]; - codes[0] = code; - } - callListenerOnCodeInput(key, code, codes, x, y); - callListenerOnRelease(key, code, false); + int code = key.mCode; + final int[] codes = mKeyDetector.newCodeArray(); + mKeyDetector.getKeyAndNearbyCodes(x, y, codes); + + // If keyboard is in manual temporary upper case state and key has manual temporary + // uppercase letter as key hint letter, alternate character code should be sent. + if (mKeyboard.isManualTemporaryUpperCase() && key.hasUppercaseLetter()) { + code = key.mHintLabel.charAt(0); + codes[0] = code; } + + // Swap the first and second values in the codes array if the primary code is not the + // first value but the second value in the array. This happens when key debouncing is + // in effect. + if (codes.length >= 2 && codes[0] != code && codes[1] == code) { + codes[1] = codes[0]; + codes[0] = code; + } + callListenerOnCodeInput(key, code, codes, x, y); + callListenerOnRelease(key, code, false); } private long mPreviousEventTime; private void printTouchEvent(String title, int x, int y, long eventTime) { - final int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); - final Key key = getKey(keyIndex); - final String code = (key == null) ? "----" : keyCodePrintable(key.mCode); + final Key key = mKeyDetector.getKeyAndNearbyCodes(x, y, null); + final String code = KeyDetector.printableCode(key); final long delta = eventTime - mPreviousEventTime; - Log.d(TAG, String.format("%s%s[%d] %4d %4d %5d %3d(%s)", title, - (mKeyAlreadyProcessed ? "-" : " "), mPointerId, x, y, delta, keyIndex, code)); + Log.d(TAG, String.format("%s%s[%d] %4d %4d %5d %s", title, + (mKeyAlreadyProcessed ? "-" : " "), mPointerId, x, y, delta, code)); mPreviousEventTime = eventTime; } - - private static String keyCodePrintable(int primaryCode) { - final String modifier = isModifierCode(primaryCode) ? " modifier" : ""; - return String.format((primaryCode < 0) ? "%4d" : "0x%02x", primaryCode) + modifier; - } } diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java index 2a25d0ca7..6c5c3e7be 100644 --- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java +++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java @@ -75,16 +75,16 @@ public class ProximityInfo { return spellCheckerProximityInfo; } - private int mNativeProximityInfo; + private long mNativeProximityInfo; static { Utils.loadNativeLibrary(); } - private native int setProximityInfoNative(int maxProximityCharsSize, int displayWidth, + private native long setProximityInfoNative(int maxProximityCharsSize, int displayWidth, int displayHeight, int gridWidth, int gridHeight, int[] proximityCharsArray, int keyCount, int[] keyXCoordinates, int[] keyYCoordinates, int[] keyWidths, int[] keyHeights, int[] keyCharCodes, float[] sweetSpotCenterX, float[] sweetSpotCenterY, float[] sweetSpotRadii); - private native void releaseProximityInfoNative(int nativeProximityInfo); + private native void releaseProximityInfoNative(long nativeProximityInfo); private final void setProximityInfo(int[][] gridNeighborKeyIndexes, int keyboardWidth, int keyboardHeight, List<Key> keys, @@ -157,7 +157,7 @@ public class ProximityInfo { } } - public int getNativeProximityInfo() { + public long getNativeProximityInfo() { return mNativeProximityInfo; } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java index b385b7a04..218793500 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java @@ -40,7 +40,6 @@ public class KeyStyles { public CharSequence getText(TypedArray a, int index); public int getInt(TypedArray a, int index, int defaultValue); public int getFlag(TypedArray a, int index, int defaultValue); - public boolean getBoolean(TypedArray a, int index, boolean defaultValue); } /* package */ static class EmptyKeyStyle implements KeyStyle { @@ -68,11 +67,6 @@ public class KeyStyles { return a.getInt(index, defaultValue); } - @Override - public boolean getBoolean(TypedArray a, int index, boolean defaultValue) { - return a.getBoolean(index, defaultValue); - } - protected static CharSequence[] parseTextArray(TypedArray a, int index) { if (!a.hasValue(index)) return null; @@ -151,12 +145,6 @@ public class KeyStyles { return super.getFlag(a, index, defaultValue) | (value != null ? value : 0); } - @Override - public boolean getBoolean(TypedArray a, int index, boolean defaultValue) { - final Boolean value = (Boolean)mAttributes.get(index); - return super.getBoolean(a, index, (value != null) ? value : defaultValue); - } - private DeclaredKeyStyle() { super(); } @@ -164,18 +152,18 @@ public class KeyStyles { private void parseKeyStyleAttributes(TypedArray keyAttr) { // TODO: Currently not all Key attributes can be declared as style. readInt(keyAttr, R.styleable.Keyboard_Key_code); + readInt(keyAttr, R.styleable.Keyboard_Key_altCode); readText(keyAttr, R.styleable.Keyboard_Key_keyLabel); readText(keyAttr, R.styleable.Keyboard_Key_keyOutputText); readText(keyAttr, R.styleable.Keyboard_Key_keyHintLabel); readTextArray(keyAttr, R.styleable.Keyboard_Key_moreKeys); - readFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelOption); + readFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags); readInt(keyAttr, R.styleable.Keyboard_Key_keyIcon); readInt(keyAttr, R.styleable.Keyboard_Key_keyIconPreview); readInt(keyAttr, R.styleable.Keyboard_Key_keyIconShifted); readInt(keyAttr, R.styleable.Keyboard_Key_maxMoreKeysColumn); readInt(keyAttr, R.styleable.Keyboard_Key_backgroundType); - readBoolean(keyAttr, R.styleable.Keyboard_Key_isRepeatable); - readBoolean(keyAttr, R.styleable.Keyboard_Key_enabled); + readFlag(keyAttr, R.styleable.Keyboard_Key_keyActionFlags); } private void readText(TypedArray a, int index) { @@ -194,11 +182,6 @@ public class KeyStyles { mAttributes.put(index, a.getInt(index, 0) | (value != null ? value : 0)); } - private void readBoolean(TypedArray a, int index) { - if (a.hasValue(index)) - mAttributes.put(index, a.getBoolean(index, false)); - } - private void readTextArray(TypedArray a, int index) { final CharSequence[] value = parseTextArray(a, index); if (value != null) @@ -235,7 +218,7 @@ public class KeyStyles { return mStyles.get(styleName); } - public KeyStyle getEmptyKeyStyle() { + public static KeyStyle getEmptyKeyStyle() { return EMPTY_KEY_STYLE; } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java index 28a53cedc..4a77e0735 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java @@ -33,7 +33,7 @@ public class KeyboardShiftState { private int mState = NORMAL; - public boolean setShifted(boolean newShiftState) { + public void setShifted(boolean newShiftState) { final int oldState = mState; if (newShiftState) { switch (oldState) { @@ -61,7 +61,6 @@ public class KeyboardShiftState { } if (DEBUG) Log.d(TAG, "setShifted(" + newShiftState + "): " + toString(oldState) + " > " + this); - return mState != oldState; } public void setShiftLocked(boolean newShiftLockState) { diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java new file mode 100644 index 000000000..fd7e77863 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java @@ -0,0 +1,155 @@ +/* + * 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.keyboard.internal; + +// TODO: Add unit tests +public class KeyboardState { + private KeyboardShiftState mKeyboardShiftState = new KeyboardShiftState(); + + // TODO: Combine these key state objects with auto mode switch state. + private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift"); + private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol"); + + public KeyboardState() { + } + + public boolean isShiftLocked() { + return mKeyboardShiftState.isShiftLocked(); + } + + public boolean isShiftLockShifted() { + return mKeyboardShiftState.isShiftLockShifted(); + } + + public boolean isShiftedOrShiftLocked() { + return mKeyboardShiftState.isShiftedOrShiftLocked(); + } + + public boolean isAutomaticTemporaryUpperCase() { + return mKeyboardShiftState.isAutomaticTemporaryUpperCase(); + } + + public boolean isManualTemporaryUpperCase() { + return mKeyboardShiftState.isManualTemporaryUpperCase(); + } + + public boolean isManualTemporaryUpperCaseFromAuto() { + return mKeyboardShiftState.isManualTemporaryUpperCaseFromAuto(); + } + + // TODO: Get rid of this method + public void setShifted(boolean shifted) { + mKeyboardShiftState.setShifted(shifted); + } + + // TODO: Get rid of this method + public void setShiftLocked(boolean shiftLocked) { + mKeyboardShiftState.setShiftLocked(shiftLocked); + } + + // TODO: Get rid of this method + public void setAutomaticTemporaryUpperCase() { + mKeyboardShiftState.setAutomaticTemporaryUpperCase(); + } + + // TODO: Get rid of this method + public boolean isShiftKeyIgnoring() { + return mShiftKeyState.isIgnoring(); + } + + // TODO: Get rid of this method + public boolean isShiftKeyReleasing() { + return mShiftKeyState.isReleasing(); + } + + // TODO: Get rid of this method + public boolean isShiftKeyMomentary() { + return mShiftKeyState.isMomentary(); + } + + // TODO: Get rid of this method + public boolean isShiftKeyPressing() { + return mShiftKeyState.isPressing(); + } + + // TODO: Get rid of this method + public boolean isShiftKeyPressingOnShifted() { + return mShiftKeyState.isPressingOnShifted(); + } + + public void onToggleCapsLock() { + mShiftKeyState.onRelease(); + } + + public void onPressSymbol() { + mSymbolKeyState.onPress(); + } + + public void onReleaseSymbol() { + mSymbolKeyState.onRelease(); + } + + public void onOtherKeyPressed() { + mShiftKeyState.onOtherKeyPressed(); + mSymbolKeyState.onOtherKeyPressed(); + } + + public void onUpdateShiftState(boolean isAlphabetMode) { + if (!isAlphabetMode) { + // In symbol keyboard mode, we should clear shift key state because only alphabet + // keyboard has shift key. + mSymbolKeyState.onRelease(); + } + } + + // TODO: Get rid of these boolean arguments. + public void onPressShift(boolean isAlphabetMode, boolean isShiftLocked, + boolean isAutomaticTemporaryUpperCase, boolean isShiftedOrShiftLocked) { + if (isAlphabetMode) { + if (isShiftLocked) { + // Shift key is pressed while caps lock state, we will treat this state as shifted + // caps lock state and mark as if shift key pressed while normal state. + mShiftKeyState.onPress(); + } else if (isAutomaticTemporaryUpperCase) { + // Shift key is pressed while automatic temporary upper case, we have to move to + // manual temporary upper case. + mShiftKeyState.onPress(); + } else if (isShiftedOrShiftLocked) { + // In manual upper case state, we just record shift key has been pressing while + // shifted state. + mShiftKeyState.onPressOnShifted(); + } else { + // In base layout, chording or manual temporary upper case mode is started. + mShiftKeyState.onPress(); + } + } else { + // In symbol mode, just toggle symbol and symbol more keyboard. + mShiftKeyState.onPress(); + } + } + + public void onReleaseShift() { + mShiftKeyState.onRelease(); + } + + @Override + public String toString() { + return "[keyboard=" + mKeyboardShiftState + + " shift=" + mShiftKeyState + + " symbol=" + mSymbolKeyState + "]"; + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/ModifierKeyState.java b/java/src/com/android/inputmethod/keyboard/internal/ModifierKeyState.java index dae73c4e4..f8620910a 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/ModifierKeyState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/ModifierKeyState.java @@ -20,7 +20,7 @@ import android.util.Log; import com.android.inputmethod.keyboard.KeyboardSwitcher; -public class ModifierKeyState { +/* package */ class ModifierKeyState { protected static final String TAG = "ModifierKeyState"; protected static final boolean DEBUG = KeyboardSwitcher.DEBUG_STATE; diff --git a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java index 08e7a7a4e..d9181f786 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java +++ b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java @@ -18,6 +18,7 @@ package com.android.inputmethod.keyboard.internal; import com.android.inputmethod.keyboard.PointerTracker; +import java.util.Iterator; import java.util.LinkedList; public class PointerTrackerQueue { @@ -27,18 +28,23 @@ public class PointerTrackerQueue { mQueue.add(tracker); } + public synchronized void remove(PointerTracker tracker) { + mQueue.remove(tracker); + } + public synchronized void releaseAllPointersOlderThan(PointerTracker tracker, long eventTime) { - if (mQueue.lastIndexOf(tracker) < 0) { + if (!mQueue.contains(tracker)) { return; } - final LinkedList<PointerTracker> queue = mQueue; - int oldestPos = 0; - for (PointerTracker t = queue.get(oldestPos); t != tracker; t = queue.get(oldestPos)) { - if (t.isModifier()) { - oldestPos++; - } else { + final Iterator<PointerTracker> it = mQueue.iterator(); + while (it.hasNext()) { + final PointerTracker t = it.next(); + if (t == tracker) { + break; + } + if (!t.isModifier()) { t.onPhantomUpEvent(t.getLastX(), t.getLastY(), eventTime); - queue.remove(oldestPos); + it.remove(); } } } @@ -48,22 +54,16 @@ public class PointerTrackerQueue { } public synchronized void releaseAllPointersExcept(PointerTracker tracker, long eventTime) { - for (PointerTracker t : mQueue) { - if (t == tracker) { - continue; + final Iterator<PointerTracker> it = mQueue.iterator(); + while (it.hasNext()) { + final PointerTracker t = it.next(); + if (t != tracker) { + t.onPhantomUpEvent(t.getLastX(), t.getLastY(), eventTime); + it.remove(); } - t.onPhantomUpEvent(t.getLastX(), t.getLastY(), eventTime); - } - mQueue.clear(); - if (tracker != null) { - mQueue.add(tracker); } } - public synchronized void remove(PointerTracker tracker) { - mQueue.remove(tracker); - } - public synchronized boolean isAnyInSlidingKeyInput() { for (final PointerTracker tracker : mQueue) { if (tracker.isInSlidingKeyInput()) { @@ -75,13 +75,12 @@ public class PointerTrackerQueue { @Override public String toString() { - StringBuilder sb = new StringBuilder("["); - for (PointerTracker tracker : mQueue) { - if (sb.length() > 1) + final StringBuilder sb = new StringBuilder(); + for (final PointerTracker tracker : mQueue) { + if (sb.length() > 0) sb.append(" "); - sb.append(String.format("%d", tracker.mPointerId)); + sb.append(tracker.mPointerId); } - sb.append("]"); - return sb.toString(); + return "[" + sb + "]"; } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/ShiftKeyState.java b/java/src/com/android/inputmethod/keyboard/internal/ShiftKeyState.java index 6617b917f..6f54b4f23 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/ShiftKeyState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/ShiftKeyState.java @@ -18,7 +18,7 @@ package com.android.inputmethod.keyboard.internal; import android.util.Log; -public class ShiftKeyState extends ModifierKeyState { +/* package */ class ShiftKeyState extends ModifierKeyState { private static final int PRESSING_ON_SHIFTED = 3; // both temporary shifted & shift locked private static final int IGNORING = 4; diff --git a/java/src/com/android/inputmethod/latin/AutoCorrection.java b/java/src/com/android/inputmethod/latin/AutoCorrection.java index 485ec511f..cd066a3d1 100644 --- a/java/src/com/android/inputmethod/latin/AutoCorrection.java +++ b/java/src/com/android/inputmethod/latin/AutoCorrection.java @@ -98,7 +98,7 @@ public class AutoCorrection { return whiteListedWord != null; } - private boolean hasAutoCorrectionForTypedWord(Map<String, Dictionary> dictionaries, + private static boolean hasAutoCorrectionForTypedWord(Map<String, Dictionary> dictionaries, WordComposer wordComposer, ArrayList<CharSequence> suggestions, CharSequence typedWord, int correctionMode) { if (TextUtils.isEmpty(typedWord)) return false; diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index b9fd57434..f0e56d346 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -46,7 +46,7 @@ public class BinaryDictionary extends Dictionary { private static final int TYPED_LETTER_MULTIPLIER = 2; private int mDicTypeId; - private int mNativeDict; + private long mNativeDict; private final int[] mInputCodes = new int[MAX_WORD_LENGTH * MAX_PROXIMITY_CHARS_SIZE]; private final char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_WORDS]; private final char[] mOutputChars_bigrams = new char[MAX_WORD_LENGTH * MAX_BIGRAMS]; @@ -107,15 +107,15 @@ public class BinaryDictionary extends Dictionary { Utils.loadNativeLibrary(); } - private native int openNative(String sourceDir, long dictOffset, long dictSize, + private native long openNative(String sourceDir, long dictOffset, long dictSize, int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength, int maxWords, int maxAlternatives); - private native void closeNative(int dict); - private native boolean isValidWordNative(int nativeData, char[] word, int wordLength); - private native int getSuggestionsNative(int dict, int proximityInfo, int[] xCoordinates, + private native void closeNative(long dict); + private native boolean isValidWordNative(long dict, char[] word, int wordLength); + private native int getSuggestionsNative(long dict, long proximityInfo, int[] xCoordinates, int[] yCoordinates, int[] inputCodes, int codesSize, int flags, char[] outputChars, int[] scores); - private native int getBigramsNative(int dict, char[] prevWord, int prevWordLength, + private native int getBigramsNative(long dict, char[] prevWord, int prevWordLength, int[] inputCodes, int inputCodesLength, char[] outputChars, int[] scores, int maxWordLength, int maxBigrams, int maxAlternatives); diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java index 739153044..c19a5a718 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java +++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java @@ -18,6 +18,8 @@ package com.android.inputmethod.latin; import com.android.inputmethod.keyboard.ProximityInfo; +import android.util.Log; + import java.util.Collection; import java.util.Collections; import java.util.List; @@ -27,7 +29,7 @@ import java.util.concurrent.CopyOnWriteArrayList; * Class for a collection of dictionaries that behave like one dictionary. */ public class DictionaryCollection extends Dictionary { - + private final String TAG = DictionaryCollection.class.getSimpleName(); protected final List<Dictionary> mDictionaries; public DictionaryCollection() { @@ -75,7 +77,21 @@ public class DictionaryCollection extends Dictionary { dict.close(); } - public void addDictionary(Dictionary newDict) { - if (null != newDict) mDictionaries.add(newDict); + // Warning: this is not thread-safe. Take necessary precaution when calling. + public void addDictionary(final Dictionary newDict) { + if (null == newDict) return; + if (mDictionaries.contains(newDict)) { + Log.w(TAG, "This collection already contains this dictionary: " + newDict); + } + mDictionaries.add(newDict); + } + + // Warning: this is not thread-safe. Take necessary precaution when calling. + public void removeDictionary(final Dictionary dict) { + if (mDictionaries.contains(dict)) { + mDictionaries.remove(dict); + } else { + Log.w(TAG, "This collection does not contain this dictionary: " + dict); + } } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 7ba7f7d27..5f446a5c4 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -157,6 +157,22 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar SUGGESTION_VISIBILILTY_HIDE_VALUE }; + // Magic space: a space that should disappear on space/apostrophe insertion, move after the + // punctuation on punctuation insertion, and become a real space on alpha char insertion. + // Weak space: a space that should be swapped only by suggestion strip punctuation. + // Double space: the state where the user pressed space twice quickly, which LatinIME + // resolved as period-space. Undoing this converts the period to a space. + // Swap punctuation: the state where a (weak or magic) space and a punctuation from the + // suggestion strip have just been swapped. Undoing this swaps them back. + private static final int SPACE_STATE_NONE = 0; + private static final int SPACE_STATE_DOUBLE = 1; + private static final int SPACE_STATE_SWAP_PUNCTUATION = 2; + private static final int SPACE_STATE_MAGIC = 3; + private static final int SPACE_STATE_WEAK = 4; + + // Current space state of the input method. This can be any of the above constants. + private int mSpaceState; + private Settings.Values mSettingsValues; private View mExtractArea; @@ -177,7 +193,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private UserDictionary mUserDictionary; private UserBigramDictionary mUserBigramDictionary; private UserUnigramDictionary mUserUnigramDictionary; - private boolean mIsUserDictionaryAvaliable; + private boolean mIsUserDictionaryAvailable; // TODO: Create an inner class to group options and pseudo-options to improve readability. // These variables are initialized according to the {@link EditorInfo#inputType}. @@ -190,12 +206,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private WordComposer mWordComposer = new WordComposer(); private CharSequence mBestWord; private boolean mHasUncommittedTypedChars; - // Magic space: a space that should disappear on space/apostrophe insertion, move after the - // punctuation on punctuation insertion, and become a real space on alpha char insertion. - private boolean mJustAddedMagicSpace; // This indicates whether the last char is a magic space. - // This indicates whether the last keypress resulted in processing of double space replacement - // with period-space. - private boolean mJustReplacedDoubleSpace; private int mCorrectionMode; private int mCommittedLength; @@ -241,9 +251,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 3; private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 4; private static final int MSG_SPACE_TYPED = 5; - private static final int MSG_KEY_TYPED = 6; - private static final int MSG_SET_BIGRAM_PREDICTIONS = 7; - private static final int MSG_PENDING_IMS_CALLBACK = 8; + private static final int MSG_SET_BIGRAM_PREDICTIONS = 6; + private static final int MSG_PENDING_IMS_CALLBACK = 7; private int mDelayBeforeFadeoutLanguageOnSpacebar; private int mDelayUpdateSuggestions; @@ -251,7 +260,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private int mDurationOfFadeoutLanguageOnSpacebar; private float mFinalFadeoutFactorOfLanguageOnSpacebar; private long mDoubleSpacesTurnIntoPeriodTimeout; - private long mIgnoreSpecialKeyTimeout; public UIHandler(LatinIME outerInstance) { super(outerInstance); @@ -271,8 +279,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar R.integer.config_final_fadeout_percentage_of_language_on_spacebar) / 100.0f; mDoubleSpacesTurnIntoPeriodTimeout = res.getInteger( R.integer.config_double_spaces_turn_into_period_timeout); - mIgnoreSpecialKeyTimeout = res.getInteger( - R.integer.config_ignore_special_key_timeout); } @Override @@ -384,28 +390,22 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return hasMessages(MSG_SPACE_TYPED); } - public void startKeyTypedTimer() { - removeMessages(MSG_KEY_TYPED); - sendMessageDelayed(obtainMessage(MSG_KEY_TYPED), mIgnoreSpecialKeyTimeout); - } - - public boolean isIgnoringSpecialKey() { - return hasMessages(MSG_KEY_TYPED); - } - // Working variables for the following methods. private boolean mIsOrientationChanging; private boolean mPendingSuccesiveImsCallback; private boolean mHasPendingStartInput; private boolean mHasPendingFinishInputView; private boolean mHasPendingFinishInput; + private EditorInfo mAppliedEditorInfo; public void startOrientationChanging() { removeMessages(MSG_PENDING_IMS_CALLBACK); resetPendingImsCallback(); mIsOrientationChanging = true; final LatinIME latinIme = getOuterInstance(); - latinIme.mKeyboardSwitcher.saveKeyboardState(); + if (latinIme.isInputViewShown()) { + latinIme.mKeyboardSwitcher.saveKeyboardState(); + } } private void resetPendingImsCallback() { @@ -414,18 +414,18 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mHasPendingStartInput = false; } - private void executePendingImsCallback(LatinIME latinIme, EditorInfo attribute, + private void executePendingImsCallback(LatinIME latinIme, EditorInfo editorInfo, boolean restarting) { if (mHasPendingFinishInputView) latinIme.onFinishInputViewInternal(mHasPendingFinishInput); if (mHasPendingFinishInput) latinIme.onFinishInputInternal(); if (mHasPendingStartInput) - latinIme.onStartInputInternal(attribute, restarting); + latinIme.onStartInputInternal(editorInfo, restarting); resetPendingImsCallback(); } - public void onStartInput(EditorInfo attribute, boolean restarting) { + public void onStartInput(EditorInfo editorInfo, boolean restarting) { if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { // Typically this is the second onStartInput after orientation changed. mHasPendingStartInput = true; @@ -436,27 +436,28 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mPendingSuccesiveImsCallback = true; } final LatinIME latinIme = getOuterInstance(); - executePendingImsCallback(latinIme, attribute, restarting); - latinIme.onStartInputInternal(attribute, restarting); + executePendingImsCallback(latinIme, editorInfo, restarting); + latinIme.onStartInputInternal(editorInfo, restarting); } } - public void onStartInputView(EditorInfo attribute, boolean restarting) { - if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { - // Typically this is the second onStartInputView after orientation changed. - resetPendingImsCallback(); - } else { - if (mPendingSuccesiveImsCallback) { - // This is the first onStartInputView after orientation changed. - mPendingSuccesiveImsCallback = false; - resetPendingImsCallback(); - sendMessageDelayed(obtainMessage(MSG_PENDING_IMS_CALLBACK), - PENDING_IMS_CALLBACK_DURATION); - } - final LatinIME latinIme = getOuterInstance(); - executePendingImsCallback(latinIme, attribute, restarting); - latinIme.onStartInputViewInternal(attribute, restarting); - } + public void onStartInputView(EditorInfo editorInfo, boolean restarting) { + if (hasMessages(MSG_PENDING_IMS_CALLBACK) && editorInfo == mAppliedEditorInfo) { + // Typically this is the second onStartInputView after orientation changed. + resetPendingImsCallback(); + } else { + if (mPendingSuccesiveImsCallback) { + // This is the first onStartInputView after orientation changed. + mPendingSuccesiveImsCallback = false; + resetPendingImsCallback(); + sendMessageDelayed(obtainMessage(MSG_PENDING_IMS_CALLBACK), + PENDING_IMS_CALLBACK_DURATION); + } + final LatinIME latinIme = getOuterInstance(); + executePendingImsCallback(latinIme, editorInfo, restarting); + latinIme.onStartInputViewInternal(editorInfo, restarting); + mAppliedEditorInfo = editorInfo; + } } public void onFinishInputView(boolean finishingInput) { @@ -466,6 +467,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } else { final LatinIME latinIme = getOuterInstance(); latinIme.onFinishInputViewInternal(finishingInput); + mAppliedEditorInfo = null; } } @@ -572,7 +574,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mUserDictionary = new UserDictionary(this, localeStr); mSuggest.setUserDictionary(mUserDictionary); - mIsUserDictionaryAvaliable = mUserDictionary.isEnabled(); + mIsUserDictionaryAvailable = mUserDictionary.isEnabled(); resetContactsDictionary(oldContactsDictionary); @@ -693,13 +695,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } @Override - public void onStartInput(EditorInfo attribute, boolean restarting) { - mHandler.onStartInput(attribute, restarting); + public void onStartInput(EditorInfo editorInfo, boolean restarting) { + mHandler.onStartInput(editorInfo, restarting); } @Override - public void onStartInputView(EditorInfo attribute, boolean restarting) { - mHandler.onStartInputView(attribute, restarting); + public void onStartInputView(EditorInfo editorInfo, boolean restarting) { + mHandler.onStartInputView(editorInfo, restarting); } @Override @@ -712,19 +714,19 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mHandler.onFinishInput(); } - private void onStartInputInternal(EditorInfo attribute, boolean restarting) { - super.onStartInput(attribute, restarting); + private void onStartInputInternal(EditorInfo editorInfo, boolean restarting) { + super.onStartInput(editorInfo, restarting); } - private void onStartInputViewInternal(EditorInfo attribute, boolean restarting) { - super.onStartInputView(attribute, restarting); + private void onStartInputViewInternal(EditorInfo editorInfo, boolean restarting) { + super.onStartInputView(editorInfo, restarting); final KeyboardSwitcher switcher = mKeyboardSwitcher; LatinKeyboardView inputView = switcher.getKeyboardView(); if (DEBUG) { - Log.d(TAG, "onStartInputView: attribute:" + ((attribute == null) ? "none" + Log.d(TAG, "onStartInputView: editorInfo:" + ((editorInfo == null) ? "none" : String.format("inputType=0x%08x imeOptions=0x%08x", - attribute.inputType, attribute.imeOptions))); + editorInfo.inputType, editorInfo.imeOptions))); } // In landscape mode, this method gets called without the input view being created. if (inputView == null) { @@ -734,7 +736,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Forward this event to the accessibility utilities, if enabled. final AccessibilityUtils accessUtils = AccessibilityUtils.getInstance(); if (accessUtils.isTouchExplorationEnabled()) { - accessUtils.onStartInputViewInternal(attribute, restarting); + accessUtils.onStartInputViewInternal(editorInfo, restarting); } mSubtypeSwitcher.updateParametersOnStartInputView(); @@ -745,22 +747,21 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // know now whether this is a password text field, because we need to know now whether we // want to enable the voice button. final VoiceProxy voiceIme = mVoiceProxy; - final int inputType = (attribute != null) ? attribute.inputType : 0; + final int inputType = (editorInfo != null) ? editorInfo.inputType : 0; voiceIme.resetVoiceStates(InputTypeCompatUtils.isPasswordInputType(inputType) || InputTypeCompatUtils.isVisiblePasswordInputType(inputType)); // The EditorInfo might have a flag that affects fullscreen mode. // Note: This call should be done by InputMethodService? updateFullscreenMode(); - initializeInputAttributes(attribute); + initializeInputAttributes(editorInfo); inputView.closing(); mEnteredText = null; mComposingStringBuilder.setLength(0); mHasUncommittedTypedChars = false; mDeleteCount = 0; - mJustAddedMagicSpace = false; - mJustReplacedDoubleSpace = false; + mSpaceState = SPACE_STATE_NONE; loadSettings(); updateCorrectionMode(); @@ -769,12 +770,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (mSuggest != null && mSettingsValues.mAutoCorrectEnabled) { mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold); } - mVoiceProxy.loadSettings(attribute, mPrefs); + mVoiceProxy.loadSettings(editorInfo, mPrefs); // This will work only when the subtype is not supported. LanguageSwitcherProxy.loadSettings(); if (mSubtypeSwitcher.isKeyboardMode()) { - switcher.loadKeyboard(attribute, mSettingsValues); + switcher.loadKeyboard(editorInfo, mSettingsValues); } if (mSuggestionsView != null) @@ -783,6 +784,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar isSuggestionsStripVisible(), /* needsInputViewShown */ false); // Delay updating suggestions because keyboard input view may not be shown at this point. mHandler.postUpdateSuggestions(); + mHandler.cancelDoubleSpacesTimer(); inputView.setKeyPreviewPopupEnabled(mSettingsValues.mKeyPreviewPopupOn, mSettingsValues.mKeyPreviewPopupDismissDelay); @@ -793,10 +795,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); } - private void initializeInputAttributes(EditorInfo attribute) { - if (attribute == null) + private void initializeInputAttributes(EditorInfo editorInfo) { + if (editorInfo == null) return; - final int inputType = attribute.inputType; + final int inputType = editorInfo.inputType; if (inputType == InputType.TYPE_NULL) { // TODO: We should honor TYPE_NULL specification. Log.i(TAG, "InputType.TYPE_NULL is specified"); @@ -805,7 +807,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final int variation = inputType & InputType.TYPE_MASK_VARIATION; if (inputClass == 0) { Log.w(TAG, String.format("Unexpected input class: inputType=0x%08x imeOptions=0x%08x", - inputType, attribute.imeOptions)); + inputType, editorInfo.imeOptions)); } mInsertSpaceOnPickSuggestionManually = false; @@ -921,6 +923,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar || newSelEnd != candidatesEnd) && mLastSelectionStart != newSelStart; final boolean candidatesCleared = candidatesStart == -1 && candidatesEnd == -1; if (!mExpectingUpdateSelection) { + if (SPACE_STATE_WEAK == mSpaceState) { + // Test for no WEAK_SPACE action because there is a race condition that may end up + // in coming here on a normal key press. We set this to NONE because after + // a cursor move, we don't want the suggestion strip to swap the space with the + // newly inserted punctuation. + mSpaceState = SPACE_STATE_NONE; + } if (((mComposingStringBuilder.length() > 0 && mHasUncommittedTypedChars) || mVoiceProxy.isVoiceInputHighlighted()) && (selectionChanged || candidatesCleared)) { @@ -938,22 +947,19 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar TextEntryState.reset(); updateSuggestions(); } - mJustAddedMagicSpace = false; // The user moved the cursor. - mJustReplacedDoubleSpace = false; } mExpectingUpdateSelection = false; mHandler.postUpdateShiftKeyState(); + // TODO: Decide to call restartSuggestionsOnWordBeforeCursorIfAtEndOfWord() or not + // here. It would probably be too expensive to call directly here but we may want to post a + // message to delay it. The point would be to unify behavior between backspace to the + // end of a word and manually put the pointer at the end of the word. // Make a note of the cursor position mLastSelectionStart = newSelStart; mLastSelectionEnd = newSelEnd; } - public void setLastSelection(int start, int end) { - mLastSelectionStart = start; - mLastSelectionEnd = end; - } - /** * This is called when the user has clicked on the extracted text view, * when running in fullscreen mode. The default implementation hides @@ -1164,25 +1170,22 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return false; } - private void swapSwapperAndSpace() { - final InputConnection ic = getCurrentInputConnection(); - if (ic == null) return; + // "ic" may be null + private void swapSwapperAndSpaceWhileInBatchEdit(final InputConnection ic) { + if (null == ic) return; CharSequence lastTwo = ic.getTextBeforeCursor(2, 0); // It is guaranteed lastTwo.charAt(1) is a swapper - else this method is not called. if (lastTwo != null && lastTwo.length() == 2 && lastTwo.charAt(0) == Keyboard.CODE_SPACE) { - ic.beginBatchEdit(); ic.deleteSurroundingText(2, 0); ic.commitText(lastTwo.charAt(1) + " ", 1); - ic.endBatchEdit(); mKeyboardSwitcher.updateShiftState(); } } - private void maybeDoubleSpace() { - if (mCorrectionMode == Suggest.CORRECTION_NONE) return; - final InputConnection ic = getCurrentInputConnection(); - if (ic == null) return; + private boolean maybeDoubleSpaceWhileInBatchEdit(final InputConnection ic) { + if (mCorrectionMode == Suggest.CORRECTION_NONE) return false; + if (ic == null) return false; final CharSequence lastThree = ic.getTextBeforeCursor(3, 0); if (lastThree != null && lastThree.length() == 3 && Utils.canBeFollowedByPeriod(lastThree.charAt(0)) @@ -1190,22 +1193,19 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar && lastThree.charAt(2) == Keyboard.CODE_SPACE && mHandler.isAcceptingDoubleSpaces()) { mHandler.cancelDoubleSpacesTimer(); - ic.beginBatchEdit(); ic.deleteSurroundingText(2, 0); ic.commitText(". ", 1); - ic.endBatchEdit(); mKeyboardSwitcher.updateShiftState(); - mJustReplacedDoubleSpace = true; - } else { - mHandler.startDoubleSpacesTimer(); + return true; } + return false; } - // "ic" must not null - private void maybeRemovePreviousPeriod(final InputConnection ic, CharSequence text) { + // "ic" must not be null + private static void maybeRemovePreviousPeriod(final InputConnection ic, CharSequence text) { // When the text's first character is '.', remove the previous period // if there is one. - CharSequence lastOne = ic.getTextBeforeCursor(1, 0); + final CharSequence lastOne = ic.getTextBeforeCursor(1, 0); if (lastOne != null && lastOne.length() == 1 && lastOne.charAt(0) == Keyboard.CODE_PERIOD && text.charAt(0) == Keyboard.CODE_PERIOD) { @@ -1213,11 +1213,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } - private void removeTrailingSpace() { - final InputConnection ic = getCurrentInputConnection(); + // "ic" may be null + private static void removeTrailingSpaceWhileInBatchEdit(final InputConnection ic) { if (ic == null) return; - - CharSequence lastOne = ic.getTextBeforeCursor(1, 0); + final CharSequence lastOne = ic.getTextBeforeCursor(1, 0); if (lastOne != null && lastOne.length() == 1 && lastOne.charAt(0) == Keyboard.CODE_SPACE) { ic.deleteSurroundingText(1, 0); @@ -1233,12 +1232,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return true; } - private boolean isAlphabet(int code) { - if (Character.isLetter(code)) { - return true; - } else { - return false; - } + private static boolean isAlphabet(int code) { + return Character.isLetter(code); } private void onSettingsKeyPressed() { @@ -1254,6 +1249,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Virtual codes representing custom requests. These are used in onCustomRequest() below. public static final int CODE_SHOW_INPUT_METHOD_PICKER = 1; + public static final int CODE_HAPTIC_AND_AUDIO_FEEDBACK = 2; @Override public boolean onCustomRequest(int requestCode) { @@ -1265,6 +1261,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return true; } return false; + case CODE_HAPTIC_AND_AUDIO_FEEDBACK: + hapticAndAudioFeedback(Keyboard.CODE_UNSPECIFIED); + return true; } return false; } @@ -1273,6 +1272,28 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return mOptionsDialog != null && mOptionsDialog.isShowing(); } + private void insertPunctuationFromSuggestionStrip(final InputConnection ic, final int code) { + final CharSequence beforeText = ic != null ? ic.getTextBeforeCursor(1, 0) : null; + final int toLeft = TextUtils.isEmpty(beforeText) ? 0 : beforeText.charAt(0); + final boolean shouldRegisterSwapPunctuation; + // If we have a space left of the cursor and it's a weak or a magic space, then we should + // swap it, and override the space state with SPACESTATE_SWAP_PUNCTUATION. + // To swap it, we fool handleSeparator to think the previous space state was a + // magic space. + if (Keyboard.CODE_SPACE == toLeft && mSpaceState == SPACE_STATE_WEAK) { + mSpaceState = SPACE_STATE_MAGIC; + shouldRegisterSwapPunctuation = true; + } else { + shouldRegisterSwapPunctuation = false; + } + onCodeInput(code, new int[] { code }, + KeyboardActionListener.NOT_A_TOUCH_COORDINATE, + KeyboardActionListener.NOT_A_TOUCH_COORDINATE); + if (shouldRegisterSwapPunctuation) { + mSpaceState = SPACE_STATE_SWAP_PUNCTUATION; + } + } + // Implementation of {@link KeyboardActionListener}. @Override public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) { @@ -1283,12 +1304,22 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mLastKeyTime = when; final KeyboardSwitcher switcher = mKeyboardSwitcher; final boolean distinctMultiTouch = switcher.hasDistinctMultitouch(); - final boolean lastStateOfJustReplacedDoubleSpace = mJustReplacedDoubleSpace; - mJustReplacedDoubleSpace = false; - boolean shouldStartKeyTypedTimer = true; + // The space state depends only on the last character pressed and its own previous + // state. Here, we revert the space state to neutral if the key is actually modifying + // the input contents (any non-shift key), which is what we should do for + // all inputs that do not result in a special state. Each character handling is then + // free to override the state as they see fit. + final int spaceState = mSpaceState; + + // TODO: Consolidate the double space timer, mLastKeyTime, and the space state. + if (primaryCode != Keyboard.CODE_SPACE) { + mHandler.cancelDoubleSpacesTimer(); + } + switch (primaryCode) { case Keyboard.CODE_DELETE: - handleBackspace(lastStateOfJustReplacedDoubleSpace); + mSpaceState = SPACE_STATE_NONE; + handleBackspace(spaceState); mDeleteCount++; mExpectingUpdateSelection = true; LatinImeLogger.logOnDelete(); @@ -1298,14 +1329,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (!distinctMultiTouch) { switcher.toggleShift(); } - shouldStartKeyTypedTimer = false; break; case Keyboard.CODE_SWITCH_ALPHA_SYMBOL: // Symbol key is handled in onPress() when device has distinct multi-touch panel. if (!distinctMultiTouch) { - switcher.changeKeyboardMode(); + switcher.toggleKeyboardMode(); } - shouldStartKeyTypedTimer = false; break; case Keyboard.CODE_CANCEL: if (!isShowingOptionDialog()) { @@ -1313,24 +1342,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } break; case Keyboard.CODE_SETTINGS: - if (!mHandler.isIgnoringSpecialKey()) { - onSettingsKeyPressed(); - } - shouldStartKeyTypedTimer = false; + onSettingsKeyPressed(); break; case Keyboard.CODE_CAPSLOCK: switcher.toggleCapsLock(); - //$FALL-THROUGH$ - case Keyboard.CODE_HAPTIC_AND_AUDIO_FEEDBACK_ONLY: - // Dummy code for haptic and audio feedbacks. - vibrate(); - playKeyClick(primaryCode); + hapticAndAudioFeedback(primaryCode); break; case Keyboard.CODE_SHORTCUT: - if (!mHandler.isIgnoringSpecialKey()) { - mSubtypeSwitcher.switchToShortcutIME(); - } - shouldStartKeyTypedTimer = false; + mSubtypeSwitcher.switchToShortcutIME(); break; case Keyboard.CODE_TAB: handleTab(); @@ -1344,10 +1363,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // To sum it up: do not update mExpectingUpdateSelection here. break; default: + mSpaceState = SPACE_STATE_NONE; if (mSettingsValues.isWordSeparator(primaryCode)) { - handleSeparator(primaryCode, x, y); + handleSeparator(primaryCode, x, y, spaceState); } else { - handleCharacter(primaryCode, keyCodes, x, y); + handleCharacter(primaryCode, keyCodes, x, y, spaceState); } mExpectingUpdateSelection = true; break; @@ -1355,9 +1375,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar switcher.onKey(primaryCode); // Reset after any single keystroke mEnteredText = null; - if (shouldStartKeyTypedTimer) { - mHandler.startKeyTypedTimer(); - } } @Override @@ -1372,9 +1389,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar ic.endBatchEdit(); mKeyboardSwitcher.updateShiftState(); mKeyboardSwitcher.onKey(Keyboard.CODE_DUMMY); - mJustAddedMagicSpace = false; + mSpaceState = SPACE_STATE_NONE; mEnteredText = text; - mHandler.startKeyTypedTimer(); } @Override @@ -1383,7 +1399,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mKeyboardSwitcher.onCancelInput(); } - private void handleBackspace(boolean justReplacedDoubleSpace) { + private void handleBackspace(final int spaceState) { if (mVoiceProxy.logAndRevertVoiceInput()) return; final InputConnection ic = getCurrentInputConnection(); @@ -1421,15 +1437,24 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } mHandler.postUpdateShiftKeyState(); + // TODO: Merge space state with TextEntryState TextEntryState.backspace(); if (TextEntryState.isUndoCommit()) { revertLastWord(ic); ic.endBatchEdit(); return; } - if (justReplacedDoubleSpace) { + if (SPACE_STATE_DOUBLE == spaceState) { if (revertDoubleSpace(ic)) { ic.endBatchEdit(); + // No need to reset mSpaceState, it has already be done (that's why we + // receive it as a parameter) + return; + } + } else if (SPACE_STATE_SWAP_PUNCTUATION == spaceState) { + if (revertSwapPunctuation(ic)) { + ic.endBatchEdit(); + // Likewise return; } } @@ -1447,10 +1472,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // inconsistent with backspacing after selecting other suggestions. revertLastWord(ic); } else { - sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); + ic.deleteSurroundingText(1, 0); if (mDeleteCount > DELETE_ACCELERATE_AT) { - sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); + ic.deleteSurroundingText(1, 0); } + restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(ic); } } ic.endBatchEdit(); @@ -1479,18 +1505,24 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } - private void handleCharacter(int primaryCode, int[] keyCodes, int x, int y) { + private void handleCharacter(final int primaryCode, final int[] keyCodes, final int x, + final int y, final int spaceState) { mVoiceProxy.handleCharacter(); - if (mJustAddedMagicSpace && mSettingsValues.isMagicSpaceStripper(primaryCode)) { - removeTrailingSpace(); + final InputConnection ic = getCurrentInputConnection(); + if (ic != null) ic.beginBatchEdit(); + if (SPACE_STATE_MAGIC == spaceState + && mSettingsValues.isMagicSpaceStripper(primaryCode)) { + removeTrailingSpaceWhileInBatchEdit(ic); } int code = primaryCode; if ((isAlphabet(code) || mSettingsValues.isSymbolExcludedFromWordSeparators(code)) && isSuggestionsRequested() && !isCursorTouchingWord()) { if (!mHasUncommittedTypedChars) { - mHasUncommittedTypedChars = true; + // Reset entirely the composing state anyway, then start composing a new word unless + // the character is a single quote. + mHasUncommittedTypedChars = (Keyboard.CODE_SINGLE_QUOTE != code); mComposingStringBuilder.setLength(0); mWordComposer.reset(); clearSuggestions(); @@ -1501,6 +1533,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (switcher.isShiftedOrShiftLocked()) { if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT || keyCodes[0] > Character.MAX_CODE_POINT) { + if (null != ic) ic.endBatchEdit(); return; } code = keyCodes[0]; @@ -1514,6 +1547,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } else { // Some keys, such as [eszett], have upper case as multi-characters. onTextInput(upperCaseString); + if (null != ic) ic.endBatchEdit(); return; } } @@ -1521,7 +1555,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (mHasUncommittedTypedChars) { mComposingStringBuilder.append((char) code); mWordComposer.add(code, keyCodes, x, y); - final InputConnection ic = getCurrentInputConnection(); if (ic != null) { // If it's the first letter, make note of auto-caps state if (mWordComposer.size() == 1) { @@ -1539,18 +1572,19 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } else { sendKeyChar((char)code); } - if (mJustAddedMagicSpace && mSettingsValues.isMagicSpaceSwapper(primaryCode)) { - swapSwapperAndSpace(); - } else { - mJustAddedMagicSpace = false; + if (SPACE_STATE_MAGIC == spaceState + && mSettingsValues.isMagicSpaceSwapper(primaryCode)) { + if (null != ic) swapSwapperAndSpaceWhileInBatchEdit(ic); } switcher.updateShiftState(); if (LatinIME.PERF_DEBUG) measureCps(); TextEntryState.typedCharacter((char) code, mSettingsValues.isWordSeparator(code), x, y); + if (null != ic) ic.endBatchEdit(); } - private void handleSeparator(int primaryCode, int x, int y) { + private void handleSeparator(final int primaryCode, final int x, final int y, + final int spaceState) { mVoiceProxy.handleSeparator(); mComposingStateManager.onFinishComposingText(); @@ -1580,21 +1614,49 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } - if (mJustAddedMagicSpace) { + final boolean swapMagicSpace; + if (Keyboard.CODE_ENTER == primaryCode && (SPACE_STATE_MAGIC == spaceState + || SPACE_STATE_SWAP_PUNCTUATION == spaceState)) { + removeTrailingSpaceWhileInBatchEdit(ic); + swapMagicSpace = false; + } else if (SPACE_STATE_MAGIC == spaceState) { if (mSettingsValues.isMagicSpaceSwapper(primaryCode)) { - sendKeyChar((char)primaryCode); - swapSwapperAndSpace(); + swapMagicSpace = true; } else { - if (mSettingsValues.isMagicSpaceStripper(primaryCode)) removeTrailingSpace(); - sendKeyChar((char)primaryCode); - mJustAddedMagicSpace = false; + swapMagicSpace = false; + if (mSettingsValues.isMagicSpaceStripper(primaryCode)) { + removeTrailingSpaceWhileInBatchEdit(ic); + } } } else { - sendKeyChar((char)primaryCode); + swapMagicSpace = false; } - if (isSuggestionsRequested() && primaryCode == Keyboard.CODE_SPACE) { - maybeDoubleSpace(); + sendKeyChar((char)primaryCode); + + if (Keyboard.CODE_SPACE == primaryCode) { + if (isSuggestionsRequested()) { + if (maybeDoubleSpaceWhileInBatchEdit(ic)) { + mSpaceState = SPACE_STATE_DOUBLE; + } else if (!isShowingPunctuationList()) { + mSpaceState = SPACE_STATE_WEAK; + } + } + + mHandler.startDoubleSpacesTimer(); + if (!isCursorTouchingWord()) { + mHandler.cancelUpdateSuggestions(); + mHandler.postUpdateBigramPredictions(); + } + } else { + if (swapMagicSpace) { + swapSwapperAndSpaceWhileInBatchEdit(ic); + mSpaceState = SPACE_STATE_MAGIC; + } + + // Set punctuation right away. onUpdateSelection will fire but tests whether it is + // already displayed or not, so it's okay. + setPunctuationSuggestions(); } TextEntryState.typedCharacter((char) primaryCode, true, x, y); @@ -1607,16 +1669,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar ic, mLastSelectionEnd - typedWord.length(), typedWord, mBestWord); } } - if (Keyboard.CODE_SPACE == primaryCode) { - if (!isCursorTouchingWord()) { - mHandler.cancelUpdateSuggestions(); - mHandler.postUpdateBigramPredictions(); - } - } else { - // Set punctuation right away. onUpdateSelection will fire but tests whether it is - // already displayed or not, so it's okay. - setPunctuationSuggestions(); - } mKeyboardSwitcher.updateShiftState(); if (ic != null) { ic.endBatchEdit(); @@ -1651,7 +1703,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public boolean isSuggestionsStripVisible() { if (mSuggestionsView == null) return false; - if (mSuggestionsView.isShowingAddToDictionaryHint() || TextEntryState.isRecorrecting()) + if (mSuggestionsView.isShowingAddToDictionaryHint()) return true; if (!isShowingSuggestionsStrip()) return false; @@ -1748,15 +1800,23 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // The whitelist should be case-insensitive, so it's not possible to be consistent with // a boolean flag. Right now this is handled with a slight hack in // WhitelistDictionary#shouldForciblyAutoCorrectFrom. + final int quotesCount = wordComposer.trailingSingleQuotesCount(); final boolean allowsToBeAutoCorrected = AutoCorrection.allowsToBeAutoCorrected( - mSuggest.getUnigramDictionaries(), typedWord, preferCapitalization()); + mSuggest.getUnigramDictionaries(), + // If the typed string ends with a single quote, for dictionary lookup purposes + // we behave as if the single quote was not here. Here, we are looking up the + // typed string in the dictionary (to avoid autocorrecting from an existing + // word, so for consistency this lookup should be made WITHOUT the trailing + // single quote. + quotesCount > 0 + ? typedWord.subSequence(0, typedWord.length() - quotesCount) : typedWord, + preferCapitalization()); if (mCorrectionMode == Suggest.CORRECTION_FULL || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) { autoCorrectionAvailable |= (!allowsToBeAutoCorrected); } // Don't auto-correct words with multiple capital letter autoCorrectionAvailable &= !wordComposer.isMostlyCaps(); - autoCorrectionAvailable &= !TextEntryState.isRecorrecting(); // Basically, we update the suggestion strip only when suggestion count > 1. However, // there is an exception: We update the suggestion strip whenever typed word's length @@ -1829,7 +1889,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mVoiceProxy.flushAndLogAllTextModificationCounters(index, suggestion, mSettingsValues.mWordSeparators); - final boolean recorrecting = TextEntryState.isRecorrecting(); final InputConnection ic = getCurrentInputConnection(); if (ic != null) { ic.beginBatchEdit(); @@ -1859,8 +1918,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar LatinImeLogger.logOnManualSuggestion( "", suggestion.toString(), index, suggestions.mWords); // Find out whether the previous character is a space. If it is, as a special case - // for punctuation entered through the suggestion strip, it should be considered - // a magic space even if it was a normal space. This is meant to help in case the user + // for punctuation entered through the suggestion strip, it should be swapped + // if it was a magic or a weak space. This is meant to help in case the user // pressed space on purpose of displaying the suggestion strip punctuation. final int rawPrimaryCode = suggestion.charAt(0); // Maybe apply the "bidi mirrored" conversions for parentheses @@ -1868,15 +1927,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final boolean isRtl = keyboard != null && keyboard.mIsRtlKeyboard; final int primaryCode = Key.getRtlParenthesisCode(rawPrimaryCode, isRtl); - final CharSequence beforeText = ic != null ? ic.getTextBeforeCursor(1, 0) : ""; - final int toLeft = (ic == null || TextUtils.isEmpty(beforeText)) - ? 0 : beforeText.charAt(0); - final boolean oldMagicSpace = mJustAddedMagicSpace; - if (Keyboard.CODE_SPACE == toLeft) mJustAddedMagicSpace = true; - onCodeInput(primaryCode, new int[] { primaryCode }, - KeyboardActionListener.NOT_A_TOUCH_COORDINATE, - KeyboardActionListener.NOT_A_TOUCH_COORDINATE); - mJustAddedMagicSpace = oldMagicSpace; + insertPunctuationFromSuggestionStrip(ic, primaryCode); + // TODO: the following endBatchEdit seems useless, check if (ic != null) { ic.endBatchEdit(); } @@ -1900,7 +1952,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar suggestion.toString(), index, suggestions.mWords); TextEntryState.acceptedSuggestion(mComposingStringBuilder.toString(), suggestion); // Follow it with a space - if (mInsertSpaceOnPickSuggestionManually && !recorrecting) { + if (mInsertSpaceOnPickSuggestionManually) { sendMagicSpace(); } @@ -1920,13 +1972,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar || !AutoCorrection.isValidWord( mSuggest.getUnigramDictionaries(), suggestion, true)); - if (!recorrecting) { - // Fool the state watcher so that a subsequent backspace will not do a revert, unless - // we just did a correction, in which case we need to stay in - // TextEntryState.State.PICKED_SUGGESTION state. - TextEntryState.typedCharacter((char) Keyboard.CODE_SPACE, true, - WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); - } + // Fool the state watcher so that a subsequent backspace will not do a revert, unless + // we just did a correction, in which case we need to stay in + // TextEntryState.State.PICKED_SUGGESTION state. + TextEntryState.typedCharacter((char) Keyboard.CODE_SPACE, true, + WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); if (!showingAddToDictionaryHint) { // If we're not showing the "Touch again to save", then show corrections again. // In case the cursor position doesn't change, make sure we show the suggestions again. @@ -1936,8 +1986,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // take a noticeable delay to update them which may feel uneasy. } if (showingAddToDictionaryHint) { - if (mIsUserDictionaryAvaliable) { - mSuggestionsView.showAddToDictionaryHint(suggestion); + if (mIsUserDictionaryAvailable) { + mSuggestionsView.showAddToDictionaryHint( + suggestion, mSettingsValues.mHintToSaveText); } else { mHandler.postUpdateSuggestions(); } @@ -2068,13 +2119,60 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return false; } - // "ic" must not null - private boolean sameAsTextBeforeCursor(final InputConnection ic, CharSequence text) { + // "ic" must not be null + private static boolean sameAsTextBeforeCursor(final InputConnection ic, CharSequence text) { CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0); return TextUtils.equals(text, beforeText); } - // "ic" must not null + // "ic" must not be null + /** + * Check if the cursor is actually at the end of a word. If so, restart suggestions on this + * word, else do nothing. + */ + private void restartSuggestionsOnWordBeforeCursorIfAtEndOfWord( + final InputConnection ic) { + // Bail out if the cursor is not at the end of a word (cursor must be preceded by + // non-whitespace, non-separator, non-start-of-text) + // Example ("|" is the cursor here) : <SOL>"|a" " |a" " | " all get rejected here. + final CharSequence textBeforeCursor = ic.getTextBeforeCursor(1, 0); + if (TextUtils.isEmpty(textBeforeCursor) + || mSettingsValues.isWordSeparator(textBeforeCursor.charAt(0))) return; + + // Bail out if the cursor is in the middle of a word (cursor must be followed by whitespace, + // separator or end of line/text) + // Example: "test|"<EOL> "te|st" get rejected here + final CharSequence textAfterCursor = ic.getTextAfterCursor(1, 0); + if (!TextUtils.isEmpty(textAfterCursor) + && !mSettingsValues.isWordSeparator(textAfterCursor.charAt(0))) return; + + // Bail out if word before cursor is 0-length or a single non letter (like an apostrophe) + // Example: " '|" gets rejected here but "I'|" and "I|" are okay + final CharSequence word = EditingUtils.getWordAtCursor(ic, mSettingsValues.mWordSeparators); + if (TextUtils.isEmpty(word)) return; + if (word.length() == 1 && !Character.isLetter(word.charAt(0))) return; + + // Okay, we are at the end of a word. Restart suggestions. + restartSuggestionsOnWordBeforeCursor(ic, word); + } + + // "ic" must not be null + private void restartSuggestionsOnWordBeforeCursor(final InputConnection ic, + final CharSequence word) { + mWordComposer.setComposingWord(word, mKeyboardSwitcher.getLatinKeyboard()); + mComposingStringBuilder.setLength(0); + mComposingStringBuilder.append(word); + // mBestWord will be set appropriately by updateSuggestions() called by the handler + mBestWord = null; + mHasUncommittedTypedChars = true; + mComposingStateManager.onStartComposingText(); + TextEntryState.restartSuggestionsOnWordBeforeCursor(); + ic.deleteSurroundingText(word.length(), 0); + ic.setComposingText(word, 1); + mHandler.postUpdateSuggestions(); + } + + // "ic" must not be null private void revertLastWord(final InputConnection ic) { if (mHasUncommittedTypedChars || mComposingStringBuilder.length() <= 0) { sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); @@ -2100,6 +2198,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Clear composing text mComposingStringBuilder.setLength(0); } else { + // Note: this relies on the last word still being held in the WordComposer + // Note: in the interest of code simplicity, we may want to just call + // restartSuggestionsOnWordBeforeCursorIfAtEndOfWord instead, but retrieving + // the old WordComposer allows to reuse the actual typed coordinates. mHasUncommittedTypedChars = true; ic.setComposingText(mComposingStringBuilder, 1); TextEntryState.backspace(); @@ -2108,7 +2210,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mHandler.postUpdateSuggestions(); } - // "ic" must not null + // "ic" must not be null private boolean revertDoubleSpace(final InputConnection ic) { mHandler.cancelDoubleSpacesTimer(); // Here we test whether we indeed have a period and a space before us. This should not @@ -2123,13 +2225,28 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return true; } + private static boolean revertSwapPunctuation(final InputConnection ic) { + // Here we test whether we indeed have a space and something else before us. This should not + // be needed, but it's there just in case something went wrong. + final CharSequence textBeforeCursor = ic.getTextBeforeCursor(2, 0); + // NOTE: This does not work with surrogate pairs. Hopefully when the keyboard is able to + // enter surrogate pairs this code will have been removed. + if (Keyboard.CODE_SPACE != textBeforeCursor.charAt(1)) + return false; + ic.beginBatchEdit(); + ic.deleteSurroundingText(2, 0); + ic.commitText(" " + textBeforeCursor.subSequence(0, 1), 1); + ic.endBatchEdit(); + return true; + } + public boolean isWordSeparator(int code) { return mSettingsValues.isWordSeparator(code); } private void sendMagicSpace() { sendKeyChar((char)Keyboard.CODE_SPACE); - mJustAddedMagicSpace = true; + mSpaceState = SPACE_STATE_MAGIC; mKeyboardSwitcher.updateShiftState(); } @@ -2155,12 +2272,16 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar loadSettings(); } + private void hapticAndAudioFeedback(int primaryCode) { + vibrate(); + playKeyClick(primaryCode); + } + @Override public void onPress(int primaryCode, boolean withSliding) { final KeyboardSwitcher switcher = mKeyboardSwitcher; if (switcher.isVibrateAndSoundFeedbackRequired()) { - vibrate(); - playKeyClick(primaryCode); + hapticAndAudioFeedback(primaryCode); } final boolean distinctMultiTouch = switcher.hasDistinctMultitouch(); if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) { diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 773efe709..7d6efa584 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -109,6 +109,7 @@ public class Settings extends InputMethodSettingsActivity public final String mSuggestPuncs; public final SuggestedWords mSuggestPuncList; private final String mSymbolsExcludedFromWordSeparators; + public final CharSequence mHintToSaveText; // From preferences: public final boolean mSoundOn; // Sound setting private to Latin IME (see mSilentModeOn) @@ -158,6 +159,7 @@ public class Settings extends InputMethodSettingsActivity mSuggestPuncs = res.getString(R.string.suggested_punctuations); // TODO: it would be nice not to recreate this each time we change the configuration mSuggestPuncList = createSuggestPuncList(mSuggestPuncs); + mHintToSaveText = context.getText(R.string.hint_add_to_dictionary); // Get the settings preferences final boolean hasVibrator = VibratorCompatWrapper.getInstance(context).hasVibrator(); @@ -299,9 +301,9 @@ public class Settings extends InputMethodSettingsActivity return mShowSettingsKey; } - public boolean isVoiceKeyEnabled(EditorInfo attribute) { + public boolean isVoiceKeyEnabled(EditorInfo editorInfo) { final boolean shortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled(); - final int inputType = (attribute != null) ? attribute.inputType : 0; + final int inputType = (editorInfo != null) ? editorInfo.inputType : 0; return shortcutImeEnabled && mVoiceKeyEnabled && !InputTypeCompatUtils.isPasswordInputType(inputType); } @@ -774,4 +776,4 @@ public class Settings extends InputMethodSettingsActivity builder.setView(v); builder.create().show(); } -}
\ No newline at end of file +} diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index caa5aac51..2a36f8266 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -20,6 +20,7 @@ import android.content.Context; import android.text.TextUtils; import android.util.Log; +import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.ProximityInfo; import java.io.File; @@ -101,11 +102,12 @@ public class Suggest implements Dictionary.WordCallback { private ArrayList<CharSequence> mSuggestions = new ArrayList<CharSequence>(); ArrayList<CharSequence> mBigramSuggestions = new ArrayList<CharSequence>(); - private CharSequence mTypedWord; + private CharSequence mConsideredWord; // TODO: Remove these member variables by passing more context to addWord() callback method private boolean mIsFirstCharCapitalized; private boolean mIsAllUpperCase; + private int mTrailingSingleQuotesCount; private int mCorrectionMode = CORRECTION_BASIC; @@ -144,7 +146,7 @@ public class Suggest implements Dictionary.WordCallback { initWhitelistAndAutocorrectAndPool(context, locale); } - private void addOrReplaceDictionary(Map<String, Dictionary> dictionaries, String key, + private static void addOrReplaceDictionary(Map<String, Dictionary> dictionaries, String key, Dictionary dict) { final Dictionary oldDict = (dict == null) ? dictionaries.remove(key) @@ -295,17 +297,20 @@ public class Suggest implements Dictionary.WordCallback { mAutoCorrection.init(); mIsFirstCharCapitalized = wordComposer.isFirstCharCapitalized(); mIsAllUpperCase = wordComposer.isAllUpperCase(); + mTrailingSingleQuotesCount = wordComposer.trailingSingleQuotesCount(); collectGarbage(mSuggestions, mPrefMaxSuggestions); Arrays.fill(mScores, 0); - // Save a lowercase version of the original word - String typedWord = wordComposer.getTypedWord(); + final String typedWord = wordComposer.getTypedWord(); + final String consideredWord = mTrailingSingleQuotesCount > 0 + ? typedWord.substring(0, typedWord.length() - mTrailingSingleQuotesCount) + : typedWord; if (typedWord != null) { // Treating USER_TYPED as UNIGRAM suggestion for logging now. LatinImeLogger.onAddSuggestedWord(typedWord, Suggest.DIC_USER_TYPED, Dictionary.DataType.UNIGRAM); } - mTypedWord = typedWord; + mConsideredWord = consideredWord; if (wordComposer.size() <= 1 && (mCorrectionMode == CORRECTION_FULL_BIGRAM || mCorrectionMode == CORRECTION_BASIC)) { @@ -321,7 +326,7 @@ public class Suggest implements Dictionary.WordCallback { for (final Dictionary dictionary : mBigramDictionaries.values()) { dictionary.getBigrams(wordComposer, prevWordForBigram, this); } - if (TextUtils.isEmpty(typedWord)) { + if (TextUtils.isEmpty(consideredWord)) { // Nothing entered: return all bigrams for the previous word int insertCount = Math.min(mBigramSuggestions.size(), mPrefMaxSuggestions); for (int i = 0; i < insertCount; ++i) { @@ -330,7 +335,7 @@ public class Suggest implements Dictionary.WordCallback { } else { // Word entered: return only bigrams that match the first char of the typed word @SuppressWarnings("null") - final char currentChar = typedWord.charAt(0); + final char currentChar = consideredWord.charAt(0); // TODO: Must pay attention to locale when changing case. final char currentCharUpper = Character.toUpperCase(currentChar); int count = 0; @@ -354,24 +359,41 @@ public class Suggest implements Dictionary.WordCallback { if (key.equals(DICT_KEY_USER_UNIGRAM) || key.equals(DICT_KEY_WHITELIST)) continue; final Dictionary dictionary = mUnigramDictionaries.get(key); - dictionary.getWords(wordComposer, this, proximityInfo); + if (mTrailingSingleQuotesCount > 0) { + final WordComposer tmpWordComposer = new WordComposer(wordComposer); + for (int i = mTrailingSingleQuotesCount - 1; i >= 0; --i) { + tmpWordComposer.deleteLast(); + } + dictionary.getWords(tmpWordComposer, this, proximityInfo); + } else { + dictionary.getWords(wordComposer, this, proximityInfo); + } } } - final String typedWordString = typedWord == null ? null : typedWord.toString(); + final String consideredWordString = + consideredWord == null ? null : consideredWord.toString(); CharSequence whitelistedWord = capitalizeWord(mIsAllUpperCase, mIsFirstCharCapitalized, - mWhiteListDictionary.getWhitelistedWord(typedWordString)); + mWhiteListDictionary.getWhitelistedWord(consideredWordString)); mAutoCorrection.updateAutoCorrectionStatus(mUnigramDictionaries, wordComposer, - mSuggestions, mScores, typedWord, mAutoCorrectionThreshold, mCorrectionMode, + mSuggestions, mScores, consideredWord, mAutoCorrectionThreshold, mCorrectionMode, whitelistedWord); if (whitelistedWord != null) { - mSuggestions.add(0, whitelistedWord); + if (mTrailingSingleQuotesCount > 0) { + final StringBuilder sb = new StringBuilder(whitelistedWord); + for (int i = mTrailingSingleQuotesCount - 1; i >= 0; --i) { + sb.appendCodePoint(Keyboard.CODE_SINGLE_QUOTE); + } + mSuggestions.add(0, sb.toString()); + } else { + mSuggestions.add(0, whitelistedWord); + } } if (typedWord != null) { - mSuggestions.add(0, typedWordString); + mSuggestions.add(0, typedWord.toString()); } Utils.removeDupes(mSuggestions); @@ -424,7 +446,7 @@ public class Suggest implements Dictionary.WordCallback { int pos = 0; // Check if it's the same word, only caps are different - if (Utils.equalsIgnoreCase(mTypedWord, word, offset, length)) { + if (Utils.equalsIgnoreCase(mConsideredWord, word, offset, length)) { // TODO: remove this surrounding if clause and move this logic to // getSuggestedWordBuilder. if (suggestions.size() > 0) { @@ -486,6 +508,9 @@ public class Suggest implements Dictionary.WordCallback { } else { sb.append(word, offset, length); } + for (int i = mTrailingSingleQuotesCount - 1; i >= 0; --i) { + sb.appendCodePoint(Keyboard.CODE_SINGLE_QUOTE); + } suggestions.add(pos, sb); if (suggestions.size() > prefMaxSuggestions) { final CharSequence garbage = suggestions.remove(prefMaxSuggestions); @@ -518,7 +543,8 @@ public class Suggest implements Dictionary.WordCallback { return -1; } - private void collectGarbage(ArrayList<CharSequence> suggestions, int prefMaxSuggestions) { + private static void collectGarbage(ArrayList<CharSequence> suggestions, + int prefMaxSuggestions) { int poolSize = StringBuilderPool.getSize(); int garbageSize = suggestions.size(); while (poolSize < prefMaxSuggestions && garbageSize > 0) { diff --git a/java/src/com/android/inputmethod/latin/SuggestionsView.java b/java/src/com/android/inputmethod/latin/SuggestionsView.java index c25ecb382..8c49ba0cf 100644 --- a/java/src/com/android/inputmethod/latin/SuggestionsView.java +++ b/java/src/com/android/inputmethod/latin/SuggestionsView.java @@ -30,7 +30,6 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Message; -import android.os.SystemClock; import android.text.Spannable; import android.text.SpannableString; import android.text.Spanned; @@ -172,7 +171,6 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, public final TextView mWordToSaveView; private final TextView mHintToSaveView; - private final CharSequence mHintToSaveText; public SuggestionsViewParams(Context context, AttributeSet attrs, int defStyle, List<TextView> words, List<View> dividers, List<TextView> infos) { @@ -228,7 +226,6 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, final LayoutInflater inflater = LayoutInflater.from(context); mWordToSaveView = (TextView)inflater.inflate(R.layout.suggestion_word, null); mHintToSaveView = (TextView)inflater.inflate(R.layout.suggestion_word, null); - mHintToSaveText = context.getText(R.string.hint_add_to_dictionary); } private static Drawable getMoreSuggestionsHint(Resources res, float textSize, int color) { @@ -445,7 +442,7 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, } public void layoutAddToDictionaryHint(CharSequence word, ViewGroup stripView, - int stripWidth) { + int stripWidth, CharSequence hintText) { final int width = stripWidth - mDividerWidth - mPadding * 2; final TextView wordView = mWordToSaveView; @@ -464,8 +461,8 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, final TextView hintView = mHintToSaveView; hintView.setTextColor(mColorAutoCorrect); final int hintWidth = width - wordWidth; - final float hintScaleX = getTextScaleX(mHintToSaveText, hintWidth, hintView.getPaint()); - hintView.setText(mHintToSaveText); + final float hintScaleX = getTextScaleX(hintText, hintWidth, hintView.getPaint()); + hintView.setText(hintText); hintView.setTextScaleX(hintScaleX); stripView.addView(hintView); setLayoutWeight( @@ -647,9 +644,9 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, && mSuggestionsStrip.getChildAt(0) == mParams.mWordToSaveView; } - public void showAddToDictionaryHint(CharSequence word) { + public void showAddToDictionaryHint(CharSequence word, CharSequence hintText) { clear(); - mParams.layoutAddToDictionaryHint(word, mSuggestionsStrip, getWidth()); + mParams.layoutAddToDictionaryHint(word, mSuggestionsStrip, getWidth(), hintText); } public boolean dismissAddToDictionaryHint() { @@ -832,8 +829,7 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, // Decided to be in the sliding input mode only when the touch point has been moved // upward. mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_SLIDING_MODE; - tracker.onShowMoreKeysPanel( - translatedX, translatedY, SystemClock.uptimeMillis(), moreKeysPanel); + tracker.onShowMoreKeysPanel(translatedX, translatedY, moreKeysPanel); } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) { // Decided to be in the modal input mode mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_MODAL_MODE; diff --git a/java/src/com/android/inputmethod/latin/TextEntryState.java b/java/src/com/android/inputmethod/latin/TextEntryState.java index 79b3bdebb..a6041b310 100644 --- a/java/src/com/android/inputmethod/latin/TextEntryState.java +++ b/java/src/com/android/inputmethod/latin/TextEntryState.java @@ -30,13 +30,10 @@ public class TextEntryState { private static final int IN_WORD = 2; private static final int ACCEPTED_DEFAULT = 3; private static final int PICKED_SUGGESTION = 4; - private static final int PUNCTUATION_AFTER_WORD = 5; - private static final int PUNCTUATION_AFTER_ACCEPTED = 6; - private static final int SPACE_AFTER_ACCEPTED = 7; - private static final int SPACE_AFTER_PICKED = 8; - private static final int UNDO_COMMIT = 9; - private static final int RECORRECTING = 10; - private static final int PICKED_RECORRECTION = 11; + private static final int PUNCTUATION_AFTER_ACCEPTED = 5; + private static final int SPACE_AFTER_ACCEPTED = 6; + private static final int SPACE_AFTER_PICKED = 7; + private static final int UNDO_COMMIT = 8; private static int sState = UNKNOWN; private static int sPreviousState = UNKNOWN; @@ -79,27 +76,11 @@ public class TextEntryState { } public static void acceptedSuggestion(CharSequence typedWord, CharSequence actualWord) { - if (sState == RECORRECTING || sState == PICKED_RECORRECTION) { - setState(PICKED_RECORRECTION); - } else { - setState(PICKED_SUGGESTION); - } + setState(PICKED_SUGGESTION); if (DEBUG) displayState("acceptedSuggestion", "typedWord", typedWord, "actualWord", actualWord); } - public static void selectedForRecorrection() { - setState(RECORRECTING); - if (DEBUG) displayState("selectedForRecorrection"); - } - - public static void onAbortRecorrection() { - if (sState == RECORRECTING || sState == PICKED_RECORRECTION) { - setState(START); - } - if (DEBUG) displayState("onAbortRecorrection"); - } - public static void typedCharacter(char c, boolean isSeparator, int x, int y) { final boolean isSpace = (c == Keyboard.CODE_SPACE); switch (sState) { @@ -123,7 +104,6 @@ public class TextEntryState { } break; case PICKED_SUGGESTION: - case PICKED_RECORRECTION: if (isSpace) { setState(SPACE_AFTER_PICKED); } else if (isSeparator) { @@ -136,7 +116,6 @@ public class TextEntryState { case START: case UNKNOWN: case SPACE_AFTER_ACCEPTED: - case PUNCTUATION_AFTER_WORD: if (!isSpace && !isSeparator) { setState(IN_WORD); } else { @@ -150,9 +129,6 @@ public class TextEntryState { setState(IN_WORD); } break; - case RECORRECTING: - setState(START); - break; } RingCharBuffer.getInstance().push(c, x, y); if (isSeparator) { @@ -170,34 +146,33 @@ public class TextEntryState { } else if (sState == UNDO_COMMIT) { setState(IN_WORD); } + // TODO: tidy up this logic. At the moment, for example, writing a word goes to + // ACCEPTED_DEFAULT, backspace will go to UNDO_COMMIT, another backspace will go to IN_WORD, + // and subsequent backspaces will leave the status at IN_WORD, even if the user backspaces + // past the end of the word. We are not in a word any more but the state is still IN_WORD. if (DEBUG) displayState("backspace"); } + public static void restartSuggestionsOnWordBeforeCursor() { + if (UNKNOWN == sState || ACCEPTED_DEFAULT == sState) { + // Here we can come from pretty much any state, except the ones that we can't + // come from after backspace, so supposedly anything except UNKNOWN and + // ACCEPTED_DEFAULT. Note : we could be in UNDO_COMMIT if + // LatinIME#revertLastWord() was calling LatinIME#restartSuggestions...() + Log.e(TAG, "Strange state change : coming from state " + sState); + } + setState(IN_WORD); + } + public static void reset() { setState(START); if (DEBUG) displayState("reset"); } - public static boolean isAcceptedDefault() { - return sState == ACCEPTED_DEFAULT; - } - - public static boolean isSpaceAfterPicked() { - return sState == SPACE_AFTER_PICKED; - } - public static boolean isUndoCommit() { return sState == UNDO_COMMIT; } - public static boolean isPunctuationAfterAccepted() { - return sState == PUNCTUATION_AFTER_ACCEPTED; - } - - public static boolean isRecorrecting() { - return sState == RECORRECTING || sState == PICKED_RECORRECTION; - } - public static String getState() { return stateName(sState); } @@ -208,13 +183,10 @@ public class TextEntryState { case IN_WORD: return "IN_WORD"; case ACCEPTED_DEFAULT: return "ACCEPTED_DEFAULT"; case PICKED_SUGGESTION: return "PICKED_SUGGESTION"; - case PUNCTUATION_AFTER_WORD: return "PUNCTUATION_AFTER_WORD"; case PUNCTUATION_AFTER_ACCEPTED: return "PUNCTUATION_AFTER_ACCEPTED"; case SPACE_AFTER_ACCEPTED: return "SPACE_AFTER_ACCEPTED"; case SPACE_AFTER_PICKED: return "SPACE_AFTER_PICKED"; case UNDO_COMMIT: return "UNDO_COMMIT"; - case RECORRECTING: return "RECORRECTING"; - case PICKED_RECORRECTION: return "PICKED_RECORRECTION"; default: return "UNKNOWN"; } } diff --git a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java index 9e656675e..3a1af9311 100644 --- a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java @@ -238,7 +238,7 @@ public class UserBigramDictionary extends ExpandableDictionary { /** * Query the database */ - private Cursor query(String selection, String[] selectionArgs) { + private static Cursor query(String selection, String[] selectionArgs) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); // main INNER JOIN frequency ON (main._id=freq.pair_id) @@ -310,7 +310,7 @@ public class UserBigramDictionary extends ExpandableDictionary { } /** Prune any old data if the database is getting too big. */ - private void checkPruneData(SQLiteDatabase db) { + private static void checkPruneData(SQLiteDatabase db) { db.execSQL("PRAGMA foreign_keys = ON;"); Cursor c = db.query(FREQ_TABLE_NAME, new String[] { FREQ_COLUMN_PAIR_ID }, null, null, null, null, null); @@ -380,7 +380,7 @@ public class UserBigramDictionary extends ExpandableDictionary { return null; } - private ContentValues getContentValues(String word1, String word2, String locale) { + private static ContentValues getContentValues(String word1, String word2, String locale) { ContentValues values = new ContentValues(3); values.put(MAIN_COLUMN_WORD1, word1); values.put(MAIN_COLUMN_WORD2, word2); @@ -388,7 +388,7 @@ public class UserBigramDictionary extends ExpandableDictionary { return values; } - private ContentValues getFrequencyContentValues(int pairId, int frequency) { + private static ContentValues getFrequencyContentValues(int pairId, int frequency) { ContentValues values = new ContentValues(2); values.put(FREQ_COLUMN_PAIR_ID, pairId); values.put(FREQ_COLUMN_FREQUENCY, frequency); diff --git a/java/src/com/android/inputmethod/latin/UserDictionary.java b/java/src/com/android/inputmethod/latin/UserDictionary.java index 0bbbf3995..3e53bb0a3 100644 --- a/java/src/com/android/inputmethod/latin/UserDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserDictionary.java @@ -134,7 +134,11 @@ public class UserDictionary extends ExpandableDictionary { final Cursor cursor = getContext().getContentResolver() .query(Words.CONTENT_URI, PROJECTION_QUERY, request.toString(), requestArguments, null); - addWords(cursor); + try { + addWords(cursor); + } finally { + if (null != cursor) cursor.close(); + } } public boolean isEnabled() { @@ -242,6 +246,5 @@ public class UserDictionary extends ExpandableDictionary { cursor.moveToNext(); } } - cursor.close(); } } diff --git a/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java b/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java index e41230b3c..de7cb5716 100644 --- a/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java @@ -206,7 +206,7 @@ public class UserUnigramDictionary extends ExpandableDictionary { } } - private Cursor query(String selection, String[] selectionArgs) { + private static Cursor query(String selection, String[] selectionArgs) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); qb.setTables(USER_UNIGRAM_DICT_TABLE_NAME); qb.setProjectionMap(sDictProjectionMap); @@ -251,7 +251,7 @@ public class UserUnigramDictionary extends ExpandableDictionary { return null; } - private ContentValues getContentValues(String word, int frequency, String locale) { + private static ContentValues getContentValues(String word, int frequency, String locale) { ContentValues values = new ContentValues(4); values.put(COLUMN_WORD, word); values.put(COLUMN_FREQUENCY, frequency); diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index b29ff1975..3d0aa09f1 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -242,7 +242,7 @@ public class Utils { UsabilityStudyLogUtils.getInstance().init(context); return sRingCharBuffer; } - private int normalize(int in) { + private static int normalize(int in) { int ret = in % BUFSIZE; return ret < 0 ? ret + BUFSIZE : ret; } @@ -465,7 +465,7 @@ public class Utils { } } - public void writeBackSpace() { + public static void writeBackSpace() { UsabilityStudyLogUtils.getInstance().write("<backspace>\t0\t0"); } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index adc5637f6..44c89f73c 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -16,9 +16,13 @@ package com.android.inputmethod.latin; +import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.KeyDetector; +import com.android.inputmethod.keyboard.LatinKeyboard; import java.util.ArrayList; +import java.util.Arrays; /** * A place to store the currently composing word with information such as adjacent key codes as well @@ -41,7 +45,9 @@ public class WordComposer { private int mCapsCount; private boolean mAutoCapitalized; - + // Cache this value for performance + private int mTrailingSingleQuotesCount; + /** * Whether the user chose to capitalize the first char of the word. */ @@ -53,6 +59,7 @@ public class WordComposer { mTypedWord = new StringBuilder(N); mXCoordinates = new int[N]; mYCoordinates = new int[N]; + mTrailingSingleQuotesCount = 0; } public WordComposer(WordComposer source) { @@ -62,11 +69,12 @@ public class WordComposer { public void init(WordComposer source) { mCodes = new ArrayList<int[]>(source.mCodes); mTypedWord = new StringBuilder(source.mTypedWord); - mXCoordinates = source.mXCoordinates; - mYCoordinates = source.mYCoordinates; + mXCoordinates = Arrays.copyOf(source.mXCoordinates, source.mXCoordinates.length); + mYCoordinates = Arrays.copyOf(source.mYCoordinates, source.mYCoordinates.length); mCapsCount = source.mCapsCount; mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; mAutoCapitalized = source.mAutoCapitalized; + mTrailingSingleQuotesCount = source.mTrailingSingleQuotesCount; } /** @@ -77,6 +85,7 @@ public class WordComposer { mTypedWord.setLength(0); mCapsCount = 0; mIsFirstCharCapitalized = false; + mTrailingSingleQuotesCount = 0; } /** @@ -126,6 +135,55 @@ public class WordComposer { mIsFirstCharCapitalized = isFirstCharCapitalized( newIndex, primaryCode, mIsFirstCharCapitalized); if (Character.isUpperCase(primaryCode)) mCapsCount++; + if (Keyboard.CODE_SINGLE_QUOTE == primaryCode) { + ++mTrailingSingleQuotesCount; + } else { + mTrailingSingleQuotesCount = 0; + } + } + + /** + * Internal method to retrieve reasonable proximity info for a character. + */ + private void addKeyInfo(final int codePoint, final LatinKeyboard keyboard, + final KeyDetector keyDetector) { + for (final Key key : keyboard.mKeys) { + if (key.mCode == codePoint) { + final int x = key.mX + key.mWidth / 2; + final int y = key.mY + key.mHeight / 2; + final int[] codes = keyDetector.newCodeArray(); + keyDetector.getKeyAndNearbyCodes(x, y, codes); + add(codePoint, codes, x, y); + return; + } + } + add(codePoint, new int[] { codePoint }, + WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); + } + + /** + * Set the currently composing word to the one passed as an argument. + * This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity. + */ + public void setComposingWord(final CharSequence word, final LatinKeyboard keyboard, + final KeyDetector keyDetector) { + reset(); + final int length = word.length(); + for (int i = 0; i < length; ++i) { + int codePoint = word.charAt(i); + addKeyInfo(codePoint, keyboard, keyDetector); + } + } + + /** + * Shortcut for the above method, this will create a new KeyDetector for the passed keyboard. + */ + public void setComposingWord(final CharSequence word, final LatinKeyboard keyboard) { + final KeyDetector keyDetector = new KeyDetector(0); + keyDetector.setKeyboard(keyboard, 0, 0); + keyDetector.setProximityCorrectionEnabled(true); + keyDetector.setProximityThreshold(keyboard.mMostCommonKeyWidth); + setComposingWord(word, keyboard, keyDetector); } /** @@ -135,7 +193,7 @@ public class WordComposer { * @param primaryCode the preferred character * @param codes array of codes based on distance from touch point */ - private void correctPrimaryJuxtapos(int primaryCode, int[] codes) { + private static void correctPrimaryJuxtapos(int primaryCode, int[] codes) { if (codes.length < 2) return; if (codes[0] > 0 && codes[1] > 0 && codes[0] != primaryCode && codes[1] == primaryCode) { codes[1] = codes[0]; @@ -158,6 +216,14 @@ public class WordComposer { if (size() == 0) { mIsFirstCharCapitalized = false; } + if (mTrailingSingleQuotesCount > 0) { + --mTrailingSingleQuotesCount; + } else { + for (int i = mTypedWord.length() - 1; i >= 0; --i) { + if (Keyboard.CODE_SINGLE_QUOTE != mTypedWord.codePointAt(i)) break; + ++mTrailingSingleQuotesCount; + } + } } /** @@ -179,6 +245,10 @@ public class WordComposer { return mIsFirstCharCapitalized; } + public int trailingSingleQuotesCount() { + return mTrailingSingleQuotesCount; + } + /** * Whether or not all of the user typed chars are upper case * @return true if all user typed chars are upper case, false otherwise diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 095c2c51c..a89ef001e 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -17,7 +17,9 @@ package com.android.inputmethod.latin.spellcheck; import android.content.Intent; +import android.content.SharedPreferences; import android.content.res.Resources; +import android.preference.PreferenceManager; import android.service.textservice.SpellCheckerService; import android.text.TextUtils; import android.util.Log; @@ -41,21 +43,27 @@ import com.android.inputmethod.latin.Utils; import com.android.inputmethod.latin.WhitelistDictionary; import com.android.inputmethod.latin.WordComposer; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Iterator; import java.util.Locale; import java.util.Map; import java.util.TreeMap; +import java.util.HashSet; /** * Service for spell checking, using LatinIME's dictionaries and mechanisms. */ -public class AndroidSpellCheckerService extends SpellCheckerService { +public class AndroidSpellCheckerService extends SpellCheckerService + implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = AndroidSpellCheckerService.class.getSimpleName(); private static final boolean DBG = false; private static final int POOL_SIZE = 2; + public static final String PREF_USE_CONTACTS_KEY = "pref_spellcheck_use_contacts"; + private static final int CAPITALIZE_NONE = 0; // No caps, or mixed case private static final int CAPITALIZE_FIRST = 1; // First only private static final int CAPITALIZE_ALL = 2; // All caps @@ -82,15 +90,72 @@ public class AndroidSpellCheckerService extends SpellCheckerService { // The threshold for a candidate to be offered as a suggestion. private double mSuggestionThreshold; - // The threshold for a suggestion to be considered "likely". - private double mLikelyThreshold; + // The threshold for a suggestion to be considered "recommended". + private double mRecommendedThreshold; + // Whether to use the contacts dictionary + private boolean mUseContactsDictionary; + private final Object mUseContactsLock = new Object(); + + private final HashSet<WeakReference<DictionaryCollection>> mDictionaryCollectionsList = + new HashSet<WeakReference<DictionaryCollection>>(); @Override public void onCreate() { super.onCreate(); mSuggestionThreshold = Double.parseDouble(getString(R.string.spellchecker_suggestion_threshold_value)); - mLikelyThreshold = - Double.parseDouble(getString(R.string.spellchecker_likely_threshold_value)); + mRecommendedThreshold = + Double.parseDouble(getString(R.string.spellchecker_recommended_threshold_value)); + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + prefs.registerOnSharedPreferenceChangeListener(this); + onSharedPreferenceChanged(prefs, PREF_USE_CONTACTS_KEY); + } + + @Override + public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) { + if (!PREF_USE_CONTACTS_KEY.equals(key)) return; + synchronized(mUseContactsLock) { + mUseContactsDictionary = prefs.getBoolean(PREF_USE_CONTACTS_KEY, true); + if (mUseContactsDictionary) { + startUsingContactsDictionaryLocked(); + } else { + stopUsingContactsDictionaryLocked(); + } + } + } + + private void startUsingContactsDictionaryLocked() { + if (null == mContactsDictionary) { + mContactsDictionary = new SynchronouslyLoadedContactsDictionary(this); + } + final Iterator<WeakReference<DictionaryCollection>> iterator = + mDictionaryCollectionsList.iterator(); + while (iterator.hasNext()) { + final WeakReference<DictionaryCollection> dictRef = iterator.next(); + final DictionaryCollection dict = dictRef.get(); + if (null == dict) { + iterator.remove(); + } else { + dict.addDictionary(mContactsDictionary); + } + } + } + + private void stopUsingContactsDictionaryLocked() { + if (null == mContactsDictionary) return; + final SynchronouslyLoadedContactsDictionary contactsDict = mContactsDictionary; + mContactsDictionary = null; + final Iterator<WeakReference<DictionaryCollection>> iterator = + mDictionaryCollectionsList.iterator(); + while (iterator.hasNext()) { + final WeakReference<DictionaryCollection> dictRef = iterator.next(); + final DictionaryCollection dict = dictRef.get(); + if (null == dict) { + iterator.remove(); + } else { + dict.removeDictionary(contactsDict); + } + } + contactsDict.close(); } @Override @@ -110,10 +175,11 @@ public class AndroidSpellCheckerService extends SpellCheckerService { private static class SuggestionsGatherer implements WordCallback { public static class Result { public final String[] mSuggestions; - public final boolean mHasLikelySuggestions; - public Result(final String[] gatheredSuggestions, final boolean hasLikelySuggestions) { + public final boolean mHasRecommendedSuggestions; + public Result(final String[] gatheredSuggestions, + final boolean hasRecommendedSuggestions) { mSuggestions = gatheredSuggestions; - mHasLikelySuggestions = hasLikelySuggestions; + mHasRecommendedSuggestions = hasRecommendedSuggestions; } } @@ -121,7 +187,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService { private final int[] mScores; private final String mOriginalText; private final double mSuggestionThreshold; - private final double mLikelyThreshold; + private final double mRecommendedThreshold; private final int mMaxLength; private int mLength = 0; @@ -131,10 +197,10 @@ public class AndroidSpellCheckerService extends SpellCheckerService { private int mBestScore = Integer.MIN_VALUE; // As small as possible SuggestionsGatherer(final String originalText, final double suggestionThreshold, - final double likelyThreshold, final int maxLength) { + final double recommendedThreshold, final int maxLength) { mOriginalText = originalText; mSuggestionThreshold = suggestionThreshold; - mLikelyThreshold = likelyThreshold; + mRecommendedThreshold = recommendedThreshold; mMaxLength = maxLength; mSuggestions = new ArrayList<CharSequence>(maxLength + 1); mScores = new int[mMaxLength]; @@ -198,19 +264,19 @@ public class AndroidSpellCheckerService extends SpellCheckerService { public Result getResults(final int capitalizeType, final Locale locale) { final String[] gatheredSuggestions; - final boolean hasLikelySuggestions; + final boolean hasRecommendedSuggestions; if (0 == mLength) { // Either we found no suggestions, or we found some BUT the max length was 0. // If we found some mBestSuggestion will not be null. If it is null, then // we found none, regardless of the max length. if (null == mBestSuggestion) { gatheredSuggestions = null; - hasLikelySuggestions = false; + hasRecommendedSuggestions = false; } else { gatheredSuggestions = EMPTY_STRING_ARRAY; final double normalizedScore = Utils.calcNormalizedScore(mOriginalText, mBestSuggestion, mBestScore); - hasLikelySuggestions = (normalizedScore > mLikelyThreshold); + hasRecommendedSuggestions = (normalizedScore > mRecommendedThreshold); } } else { if (DBG) { @@ -244,15 +310,15 @@ public class AndroidSpellCheckerService extends SpellCheckerService { final CharSequence bestSuggestion = mSuggestions.get(0); final double normalizedScore = Utils.calcNormalizedScore(mOriginalText, bestSuggestion, bestScore); - hasLikelySuggestions = (normalizedScore > mLikelyThreshold); + hasRecommendedSuggestions = (normalizedScore > mRecommendedThreshold); if (DBG) { Log.i(TAG, "Best suggestion : " + bestSuggestion + ", score " + bestScore); Log.i(TAG, "Normalized score = " + normalizedScore - + " (threshold " + mLikelyThreshold - + ") => hasLikelySuggestions = " + hasLikelySuggestions); + + " (threshold " + mRecommendedThreshold + + ") => hasRecommendedSuggestions = " + hasRecommendedSuggestions); } } - return new Result(gatheredSuggestions, hasLikelySuggestions); + return new Result(gatheredSuggestions, hasRecommendedSuggestions); } } @@ -273,13 +339,15 @@ public class AndroidSpellCheckerService extends SpellCheckerService { for (Dictionary dict : oldWhitelistDictionaries.values()) { dict.close(); } - if (null != mContactsDictionary) { - // The synchronously loaded contacts dictionary should have been in one - // or several pools, but it is shielded against multiple closing and it's - // safe to call it several times. - final SynchronouslyLoadedContactsDictionary dictToClose = mContactsDictionary; - mContactsDictionary = null; - dictToClose.close(); + synchronized(mUseContactsLock) { + if (null != mContactsDictionary) { + // The synchronously loaded contacts dictionary should have been in one + // or several pools, but it is shielded against multiple closing and it's + // safe to call it several times. + final SynchronouslyLoadedContactsDictionary dictToClose = mContactsDictionary; + mContactsDictionary = null; + dictToClose.close(); + } } return false; } @@ -314,11 +382,16 @@ public class AndroidSpellCheckerService extends SpellCheckerService { mWhitelistDictionaries.put(localeStr, whitelistDictionary); } dictionaryCollection.addDictionary(whitelistDictionary); - if (null == mContactsDictionary) { - mContactsDictionary = new SynchronouslyLoadedContactsDictionary(this); + synchronized(mUseContactsLock) { + if (mUseContactsDictionary) { + if (null == mContactsDictionary) { + mContactsDictionary = new SynchronouslyLoadedContactsDictionary(this); + } + } + dictionaryCollection.addDictionary(mContactsDictionary); + mDictionaryCollectionsList.add( + new WeakReference<DictionaryCollection>(dictionaryCollection)); } - // TODO: add a setting to use or not contacts when checking spelling - dictionaryCollection.addDictionary(mContactsDictionary); return new DictAndProximity(dictionaryCollection, proximityInfo); } @@ -342,10 +415,31 @@ public class AndroidSpellCheckerService extends SpellCheckerService { } private static class AndroidSpellCheckerSession extends Session { + private static final int SCRIPT_LATIN = 0; + private static final int SCRIPT_CYRILLIC = 1; + private static final TreeMap<String, Integer> mLanguageToScript; + static { + // List of the supported languages and their associated script. We won't check + // words written in another script than the selected script, because we know we + // don't have those in our dictionary so we will underline everything and we + // will never have any suggestions, so it makes no sense checking them. + mLanguageToScript = new TreeMap<String, Integer>(); + mLanguageToScript.put("en", SCRIPT_LATIN); + mLanguageToScript.put("fr", SCRIPT_LATIN); + mLanguageToScript.put("de", SCRIPT_LATIN); + mLanguageToScript.put("nl", SCRIPT_LATIN); + mLanguageToScript.put("cs", SCRIPT_LATIN); + mLanguageToScript.put("es", SCRIPT_LATIN); + mLanguageToScript.put("it", SCRIPT_LATIN); + mLanguageToScript.put("ru", SCRIPT_CYRILLIC); + } + // Immutable, but need the locale which is not available in the constructor yet private DictionaryPool mDictionaryPool; // Likewise private Locale mLocale; + // Cache this for performance + private int mScript; // One of SCRIPT_LATIN or SCRIPT_CYRILLIC for now. private final AndroidSpellCheckerService mService; @@ -358,17 +452,56 @@ public class AndroidSpellCheckerService extends SpellCheckerService { final String localeString = getLocale(); mDictionaryPool = mService.getDictionaryPool(localeString); mLocale = LocaleUtils.constructLocaleFromString(localeString); + final Integer script = mLanguageToScript.get(mLocale.getLanguage()); + if (null == script) { + throw new RuntimeException("We have been called with an unsupported language: \"" + + mLocale.getLanguage() + "\". Framework bug?"); + } + mScript = script; + } + + /* + * Returns whether the code point is a letter that makes sense for the specified + * locale for this spell checker. + * The dictionaries supported by Latin IME are described in res/xml/spellchecker.xml + * and is limited to EFIGS languages and Russian. + * Hence at the moment this explicitly tests for Cyrillic characters or Latin characters + * as appropriate, and explicitly excludes CJK, Arabic and Hebrew characters. + */ + private static boolean isLetterCheckableByLanguage(final int codePoint, + final int script) { + switch (script) { + case SCRIPT_LATIN: + // Our supported latin script dictionaries (EFIGS) at the moment only include + // characters in the C0, C1, Latin Extended A and B, IPA extensions unicode + // blocks. As it happens, those are back-to-back in the code range 0x40 to 0x2AF, + // so the below is a very efficient way to test for it. As for the 0-0x3F, it's + // excluded from isLetter anyway. + return codePoint <= 0x2AF && Character.isLetter(codePoint); + case SCRIPT_CYRILLIC: + // All Cyrillic characters are in the 400~52F block. There are some in the upper + // Unicode range, but they are archaic characters that are not used in modern + // russian and are not used by our dictionary. + return codePoint >= 0x400 && codePoint <= 0x52F && Character.isLetter(codePoint); + default: + // Should never come here + throw new RuntimeException("Impossible value of script: " + script); + } } /** * Finds out whether a particular string should be filtered out of spell checking. * - * This will loosely match URLs, numbers, symbols. + * This will loosely match URLs, numbers, symbols. To avoid always underlining words that + * we know we will never recognize, this accepts a script identifier that should be one + * of the SCRIPT_* constants defined above, to rule out quickly characters from very + * different languages. * * @param text the string to evaluate. + * @param script the identifier for the script this spell checker recognizes * @return true if we should filter this text out, false otherwise */ - private boolean shouldFilterOut(final String text) { + private static boolean shouldFilterOut(final String text, final int script) { if (TextUtils.isEmpty(text) || text.length() <= 1) return true; // TODO: check if an equivalent processing can't be done more quickly with a @@ -376,7 +509,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService { // Filter by first letter final int firstCodePoint = text.codePointAt(0); // Filter out words that don't start with a letter or an apostrophe - if (!Character.isLetter(firstCodePoint) + if (!isLetterCheckableByLanguage(firstCodePoint, script) && '\'' != firstCodePoint) return true; // Filter contents @@ -389,7 +522,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService { // words or a URI - in either case we don't want to spell check that if ('@' == codePoint || '/' == codePoint) return true; - if (Character.isLetter(codePoint)) ++letterCount; + if (isLetterCheckableByLanguage(codePoint, script)) ++letterCount; } // Guestimate heuristic: perform spell checking if at least 3/4 of the characters // in this word are letters @@ -408,7 +541,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService { try { final String text = textInfo.getText(); - if (shouldFilterOut(text)) { + if (shouldFilterOut(text, mScript)) { DictAndProximity dictInfo = null; try { dictInfo = mDictionaryPool.takeOrGetNull(); @@ -426,7 +559,8 @@ public class AndroidSpellCheckerService extends SpellCheckerService { // TODO: Don't gather suggestions if the limit is <= 0 unless necessary final SuggestionsGatherer suggestionsGatherer = new SuggestionsGatherer(text, - mService.mSuggestionThreshold, mService.mLikelyThreshold, suggestionsLimit); + mService.mSuggestionThreshold, mService.mRecommendedThreshold, + suggestionsLimit); final WordComposer composer = new WordComposer(); final int length = text.length(); for (int i = 0; i < length; ++i) { @@ -475,7 +609,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService { + suggestionsLimit); Log.i(TAG, "IsInDict = " + isInDict); Log.i(TAG, "LooksLikeTypo = " + (!isInDict)); - Log.i(TAG, "HasLikelySuggestions = " + result.mHasLikelySuggestions); + Log.i(TAG, "HasRecommendedSuggestions = " + result.mHasRecommendedSuggestions); if (null != result.mSuggestions) { for (String suggestion : result.mSuggestions) { Log.i(TAG, suggestion); @@ -483,10 +617,12 @@ public class AndroidSpellCheckerService extends SpellCheckerService { } } - // TODO: actually use result.mHasLikelySuggestions final int flags = (isInDict ? SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY - : SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO); + : SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) + | (result.mHasRecommendedSuggestions + ? SuggestionsInfo.RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS + : 0); return new SuggestionsInfo(flags, result.mSuggestions); } catch (RuntimeException e) { // Don't kill the keyboard if there is a bug in the spell checker |