diff options
416 files changed, 18237 insertions, 12014 deletions
diff --git a/Android.mk b/Android.mk index 8f1acc55a..91b2fbbb0 100644 --- a/Android.mk +++ b/Android.mk @@ -12,6 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -LOCAL_PATH := $(call my-dir) - -include $(call all-makefiles-under,$(LOCAL_PATH)) +include $(call all-subdir-makefiles) diff --git a/dictionaries/sample.xml b/dictionaries/sample.xml index 85233b63a..ad98f2b6f 100644 --- a/dictionaries/sample.xml +++ b/dictionaries/sample.xml @@ -2,7 +2,9 @@ for use by the Latin IME. The format of the word list is a flat list of word entries. Each entry has a frequency between 255 and 0. - Highest frequency words get more weight in the prediction algorithm. + Highest frequency words get more weight in the prediction algorithm. As a + special case, a weight of 0 is taken to mean profanity - words that should + not be considered a typo, but that should never be suggested explicitly. You can capitalize words that must always be capitalized, such as "January". You can have a capitalized and a non-capitalized word as separate entries, such as "robin" and "Robin". @@ -13,4 +15,3 @@ <w f="128">sample</w> <w f="1">wordlist</w> </wordlist> - diff --git a/java/Android.mk b/java/Android.mk index e9fa52ef3..fd71d82e0 100644 --- a/java/Android.mk +++ b/java/Android.mk @@ -1,3 +1,17 @@ +# 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. + LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) @@ -9,7 +23,9 @@ LOCAL_PACKAGE_NAME := LatinIME LOCAL_CERTIFICATE := shared +# We want to package libjni_latinime.so into the apk. LOCAL_JNI_SHARED_LIBRARIES := libjni_latinime +# We want to install libjni_latinime.so to the system partition if LatinIME gets installed. LOCAL_REQUIRED_MODULES := libjni_latinime LOCAL_STATIC_JAVA_LIBRARIES := android-common diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml index b0525326c..e663c90f2 100644 --- a/java/AndroidManifest.xml +++ b/java/AndroidManifest.xml @@ -5,16 +5,15 @@ <uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.READ_USER_DICTIONARY" /> - <uses-permission android:name="android.permission.WRITE_USER_DICTIONARY" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> - <application android:label="@string/english_ime_name" + <application android:label="@string/aosp_android_keyboard_ime_name" android:icon="@drawable/ic_ime_settings" android:backupAgent="BackupAgent" android:killAfterRestore="false"> <service android:name="LatinIME" - android:label="@string/english_ime_name" + android:label="@string/aosp_android_keyboard_ime_name" android:permission="android.permission.BIND_INPUT_METHOD"> <intent-filter> <action android:name="android.view.InputMethod" /> diff --git a/java/proguard.flags b/java/proguard.flags index 33af890ec..5ce0c273c 100644 --- a/java/proguard.flags +++ b/java/proguard.flags @@ -35,6 +35,6 @@ *; } --keep class com.android.inputmethod.keyboard.internal.MiniKeyboardBuilder$MiniKeyboardParams { +-keep class com.android.inputmethod.keyboard.MoreKeysKeyboard$Builder$MoreKeysKeyboardParams { <init>(...); } diff --git a/java/res/anim/mini_keyboard_fadein.xml b/java/res/anim/more_keys_keyboard_fadein.xml index f80e8b8de..c781f36ad 100644 --- a/java/res/anim/mini_keyboard_fadein.xml +++ b/java/res/anim/more_keys_keyboard_fadein.xml @@ -25,5 +25,5 @@ <alpha android:fromAlpha="0.5" android:toAlpha="1.0" - android:duration="@integer/config_mini_keyboard_fadein_anim_time" /> + android:duration="@integer/config_more_keys_keyboard_fadein_anim_time" /> </set> diff --git a/java/res/anim/mini_keyboard_fadeout.xml b/java/res/anim/more_keys_keyboard_fadeout.xml index 535b100ae..32fae6bd8 100644 --- a/java/res/anim/mini_keyboard_fadeout.xml +++ b/java/res/anim/more_keys_keyboard_fadeout.xml @@ -25,5 +25,5 @@ <alpha android:fromAlpha="1.0" android:toAlpha="0.0" - android:duration="@integer/config_mini_keyboard_fadeout_anim_time" /> + android:duration="@integer/config_more_keys_keyboard_fadeout_anim_time" /> </set> diff --git a/java/res/layout/input_view.xml b/java/res/layout/input_view.xml index 2e0cddc28..b9451f8ae 100644 --- a/java/res/layout/input_view.xml +++ b/java/res/layout/input_view.xml @@ -43,7 +43,7 @@ android:layout_width="@dimen/suggestions_strip_padding" android:layout_height="@dimen/suggestions_strip_height" style="?attr/suggestionsStripBackgroundStyle" /> - <com.android.inputmethod.latin.SuggestionsView + <com.android.inputmethod.latin.suggestions.SuggestionsView android:id="@+id/suggestions_view" android:layout_weight="1.0" android:layout_width="0dp" diff --git a/java/res/layout/mini_keyboard.xml b/java/res/layout/more_keys_keyboard.xml index 6964ec5d6..89161c6b4 100644 --- a/java/res/layout/mini_keyboard.xml +++ b/java/res/layout/more_keys_keyboard.xml @@ -22,11 +22,11 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" - style="?attr/miniKeyboardPanelStyle" + style="?attr/moreKeysKeyboardPanelStyle" > - <com.android.inputmethod.keyboard.MiniKeyboardView + <com.android.inputmethod.keyboard.MoreKeysKeyboardView xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - android:id="@+id/mini_keyboard_view" + android:id="@+id/more_keys_keyboard_view" android:layout_alignParentBottom="true" android:layout_width="wrap_content" android:layout_height="wrap_content" diff --git a/java/res/layout/more_suggestions.xml b/java/res/layout/more_suggestions.xml index 6aa82e197..34f54f974 100644 --- a/java/res/layout/more_suggestions.xml +++ b/java/res/layout/more_suggestions.xml @@ -22,9 +22,9 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" - style="?attr/miniKeyboardPanelStyle" + style="?attr/moreKeysKeyboardPanelStyle" > - <com.android.inputmethod.latin.MoreSuggestionsView + <com.android.inputmethod.latin.suggestions.MoreSuggestionsView xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" android:id="@+id/more_suggestions_view" android:layout_alignParentBottom="true" diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml index 36c9d4bc4..0ca0e9005 100644 --- a/java/res/values-af/strings.xml +++ b/java/res/values-af/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Android-sleutelbord"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android-sleutelbord (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Android-sleutelbordinstellings"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Invoeropsies"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Android-korrigering"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Speltoetser se instellings"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Gebruik nabyheidsdata"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Gebruik \'n sleutelbordagtige nabyheidsalgoritme vir die speltoetser"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Soek kontakname op"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Speltoetser gebruik inskrywings uit jou kontaklys"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibreer met sleuteldruk"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Klank met sleuteldruk"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Opspring met sleuteldruk"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Gestoor"</string> <string name="label_go_key" msgid="1635148082137219148">"Gaan"</string> <string name="label_next_key" msgid="362972844525672568">"Volgende"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Klaar"</string> <string name="label_send_key" msgid="2815056534433717444">"Stuur"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Steminvoering"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Glimlag-gesiggie"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Komma"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Tydperk"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Links-hakie"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Regs-hakie"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Dubbelpunt"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Kommapunt"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Uitroepteken"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Vraagteken"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Dubbel-aanhalingsteken"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Enkel-aanhalingsteken"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punt"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Vierkantswortel"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Handelsmerk"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Per adres"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Ster"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Pond"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Ellips"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Onderste dubbel-aanhalingsteken"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Steminvoering"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Steminvoering vir jou taal word nie tans ondersteun nie, maar werk wel in Engels."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Steminvoer gebruik Google se spraakherkenning. "<a href="http://m.google.com/privacy">"Die Mobiel-privaatheidsbeleid"</a>" is van toepassing."</string> @@ -144,10 +128,9 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Aktiveer gebruikerterugvoer"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Help hierdie invoermetode-redigeerder te verbeter deur gebruikstatistiek en omvalverslae outomaties na Google te stuur."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Sleutelbordtema"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Duitse QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Engels (VK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Engels (VS)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Bruikbaarheidstudie-modus"</string> - <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Vibrasie-tydsduur met sleuteldruk"</string> - <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Volume met sleuteldruk"</string> + <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Sleuteldruk se vibrasie-tydsduurinstellings"</string> + <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Sleuteldruk se klankvolume-instellings"</string> </resources> diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml index d5280bc64..ea64daeff 100644 --- a/java/res/values-am/strings.xml +++ b/java/res/values-am/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"የAndroid ቁልፍሰሌዳ"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"የAndroid ቁልፍ ሰሌዳ (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"የAndroid ቁልፍሰሌዳ ቅንብሮች"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"ግቤት አማራጮች"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"የAndroid ማስተካከያ"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"የፊደል አራሚ ቅንብሮች"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"የቀረቤታ ውሂብ ተጠቀም"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"ለፊደል አራሚ የሰሌዳ ቁልፍ አይነት የቀረበ ስልተ ቀመር ተጠቀም"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"የእውቅያ ስሞችን ተመልከት"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"ፊደል አራሚ ከእውቅያ ዝርዝርህ የገቡትን ይጠቀማል"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"በቁልፍመጫንጊዜ አንዝር"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"በቁልፍ መጫን ላይ የሚወጣ ድምፅ"</string> <string name="popup_on_keypress" msgid="123894815723512944">"ቁልፍ ጫን ላይ ብቅ ባይ"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : ተቀምጧል"</string> <string name="label_go_key" msgid="1635148082137219148">"ሂድ"</string> <string name="label_next_key" msgid="362972844525672568">"በመቀጠል"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"ተከናውኗል"</string> <string name="label_send_key" msgid="2815056534433717444">" ይላኩ"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"የድምፅ ግቤ ት"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"የፈገግታ ፊት"</string> <string name="spoken_description_return" msgid="8178083177238315647">"ተመለስ"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"ነጠላ ሰረዝ"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"ክፍለ ጊዜ"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"የግራ ቅንፍ"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"የቀኝ ቅንፍ"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"ሁለት ነጥብ"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"ድርብ ሰረዝ"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"ቃል አጋኖ"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"ጥያቄ ምልክት"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"ድርብ ጥቅስ"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"ነጠላ ትምህርተ ጥቅስ"</string> <string name="spoken_description_dot" msgid="40711082435231673">"ነጥብ"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"ስክዌር ሩት"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"ዴልታ"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"የንግድምልክት"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"መጠንቀቅ"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"ኮከብ"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"ፓውንድ"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Ellipsis"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"ዝቅ ያለ ድርብ ትምህርተ ጥቅስ"</string> <string name="voice_warning_title" msgid="4419354150908395008">"የድምፅ ግቤ ት"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"የድምፅ ግቤት በአሁኑ ጊዜ ለእርስዎን ቋንቋ አይደግፍም፣ ግን በእንግሊዘኛ ይሰራል።"</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"የድምፅ ግቤት የGoogleን ንግግር ለይቶ ማወቂያ ይጠቀማል።"<a href="http://m.google.com/privacy">"የተንቀሳቃሽ ስልክ ግላዊ ፖሊሲ"</a>" ይተገበራል።"</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"የተጠቃሚ ግብረ ምላሽ አንቃ"</string> <string name="prefs_description_log" msgid="5827825607258246003">"ወደ Google የተሰናከለ ሪፖርቶች እና አጠቃቀም ስታስቲክስ በራስ ሰር በመላክ ይህን ግቤት ሜተድ አርትኢ እገዛ ያሻሽላል።"</string> <string name="keyboard_layout" msgid="8451164783510487501">"የቁልፍ ሰሌዳ ገጽታ"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"የጀመርን QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"እንግሊዘኛ (የታላቋ ብሪታንያ)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"እንግሊዘኛ (ዩ.ኤስ)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"የተገልጋይነት ጥናት ሁነታ"</string> diff --git a/java/res/values-ar/donottranslate-more-keys.xml b/java/res/values-ar/donottranslate-more-keys.xml index cde686084..df093b3c9 100644 --- a/java/res/values-ar/donottranslate-more-keys.xml +++ b/java/res/values-ar/donottranslate-more-keys.xml @@ -38,7 +38,7 @@ <!-- In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. --> <!-- TODO: Will introduce "grouping marks" to the more characters specification. --> <string name="more_keys_for_punctuation">"\u060c,\u061b,\u061f,!,:,-,/,\',\",\u0640\u0640\u0640|\u0640,\u064e,\u0650,\u064b,\u064d,\u0670,\u0656,\u0655,\u0654,\u0653,\u0652,\u0651,\u064c,\u064f"</string> - <integer name="mini_keyboard_column_for_punctuation">9</integer> + <integer name="more_keys_keyboard_column_for_punctuation">9</integer> <string name="keyhintlabel_for_punctuation">\u064b</string> <string name="keylabel_for_symbols_1">"١"</string> <string name="keylabel_for_symbols_2">"٢"</string> @@ -50,18 +50,18 @@ <string name="keylabel_for_symbols_8">"٨"</string> <string name="keylabel_for_symbols_9">"٩"</string> <string name="keylabel_for_symbols_0">"٠"</string> - <string name="more_keys_for_symbols_1">1</string> - <string name="more_keys_for_symbols_2">2</string> - <string name="more_keys_for_symbols_3">3</string> - <string name="more_keys_for_symbols_4">4</string> - <string name="more_keys_for_symbols_5">5</string> - <string name="more_keys_for_symbols_6">6</string> - <string name="more_keys_for_symbols_7">7</string> - <string name="more_keys_for_symbols_8">8</string> - <string name="more_keys_for_symbols_9">9</string> + <string name="additional_more_keys_for_symbols_1">1</string> + <string name="additional_more_keys_for_symbols_2">2</string> + <string name="additional_more_keys_for_symbols_3">3</string> + <string name="additional_more_keys_for_symbols_4">4</string> + <string name="additional_more_keys_for_symbols_5">5</string> + <string name="additional_more_keys_for_symbols_6">6</string> + <string name="additional_more_keys_for_symbols_7">7</string> + <string name="additional_more_keys_for_symbols_8">8</string> + <string name="additional_more_keys_for_symbols_9">9</string> <!-- \u066b: ARABIC DECIMAL SEPARATOR \u066c: ARABIC THOUSANDS SEPARATOR --> - <string name="more_keys_for_symbols_0">0,\u066b,\u066c</string> + <string name="additional_more_keys_for_symbols_0">0,\u066b,\u066c</string> <string name="keylabel_for_comma">\u060c</string> <string name="keylabel_for_f1">\u060c</string> <string name="keylabel_for_symbols_question">\u061f</string> @@ -70,10 +70,8 @@ <string name="keylabel_for_symbols_percent">\u066a</string> <string name="more_keys_for_comma">,</string> <string name="more_keys_for_f1">,</string> - <!-- @icon/3 is iconSettingsKey --> - <string name="more_keys_for_f1_settings">\\,,\@icon/3|\@integer/key_settings</string> - <!-- @icon/7 is iconTabKey --> - <string name="more_keys_for_f1_navigate">\\,,\@icon/7|\@integer/key_tab</string> + <string name="more_keys_for_f1_settings">\\,,\@icon/settingsKey|\@integer/key_settings</string> + <string name="more_keys_for_f1_navigate">\\,,\@icon/tabKey|\@integer/key_tab</string> <string name="more_keys_for_symbols_question">\?</string> <string name="more_keys_for_symbols_semicolon">;</string> <string name="more_keys_for_symbols_percent">%,‰</string> @@ -104,8 +102,43 @@ <string name="more_keys_for_bullet">♪</string> <!-- \u066d: ARABIC FIVE POINTED STAR --> <string name="more_keys_for_star">★,\u066d</string> - <!-- \ufd3e: ORNATE LEFT PARENTHESIS --> - <string name="more_keys_for_left_parenthesis">[,{,<,\ufd3e</string> - <!-- \ufd3f: ORNATE RIGHT PARENTHESIS --> - <string name="more_keys_for_right_parenthesis">],},>,\ufd3f</string> + <!-- The all letters need to be mirrored are found at + http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt --> + <integer name="keycode_for_left_parenthesis">0x0029</integer> + <integer name="keycode_for_right_parenthesis">0x0028</integer> + <!-- \ufd3e: ORNATE LEFT PARENTHESIS + \ufd3f: ORNATE RIGHT PARENTHESIS --> + <string name="more_keys_for_left_parenthesis">[|],{|},<|>,\ufd3e|\ufd3f</string> + <string name="more_keys_for_right_parenthesis">]|[,}|{,>|<,\ufd3f|\ufd3e</string> + <integer name="keycode_for_less_than">0x003e</integer> + <integer name="keycode_for_greater_than">0x003c</integer> + <!-- \u2264: LESS-THAN OR EQUAL TO + \u2265: GREATER-THAN EQUAL TO + \u00ab: LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + \u00bb: RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + \u2039: SINGLE LEFT-POINTING ANGLE QUOTATION MARK + \u203a: SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + The following characters don't need BIDI mirroring. + \u2018: LEFT SINGLE QUOTATION MARK + \u2019: RIGHT SINGLE QUOTATION MARK + \u201a: SINGLE LOW-9 QUOTATION MARK + \u201b: SINGLE HIGH-REVERSED-9 QUOTATION MARK + \u201c: LEFT DOUBLE QUOTATION MARK + \u201d: RIGHT DOUBLE QUOTATION MARK + \u201e: DOUBLE LOW-9 QUOTATION MARK + \u201f: DOUBLE HIGH-REVERSED-9 QUOTATION MARK --> + <string name="more_keys_for_less_than">\u2264|\u2265,\u00ab|\u00bb,\u2039|\u203a</string> + <string name="more_keys_for_greater_than">\u2265|\u2264,\u00bb|\u00ab,\u203a|\u2039</string> + <integer name="keycode_for_left_square_bracket">0x005d</integer> + <integer name="keycode_for_right_square_bracket">0x005b</integer> + <integer name="keycode_for_left_curly_bracket">0x007d</integer> + <integer name="keycode_for_right_curly_bracket">0x007b</integer> + <!-- Note: Neither DroidSans nor Roboto have a glyph for DOUBLE HIGH-REVERSED-9 QUOTATION MARK. --> + <!-- <string name="more_keys_for_double_quote">\u201c,\u201d,\u201e,\u201f,\u00ab,\u00bb</string> --> + <!-- The 4-more keys will be displayed in order of "3,1,2,4". --> + <string name="more_keys_for_double_quote">\u201d,\u00ab|\u00bb,\u201c,\u00bb|\u00ab</string> + <!-- Note: Neither DroidSans nor Roboto have a glyph for DOUBLE HIGH-REVERSED-9 QUOTATION MARK. --> + <!-- <string name="more_keys_for_tablet_double_quote">\u201c,\u201d,\u201e,\u201f,\u00ab,\u00bb,\u2018,\u2019,\u201a,\u201b</string> --> + <!-- The 8-more keys with maxMoreKeysColumn=4 will be displayed in order of "3,1,2,4|7,5,6,8". --> + <string name="more_keys_for_tablet_double_quote">\u201d,\u00ab|\u00bb,\u201c,\u00bb|\u00ab,\u2019,\u201a,\u2018,\u201b</string> </resources> diff --git a/java/res/values-ar/donottranslate.xml b/java/res/values-ar/donottranslate.xml new file mode 100644 index 000000000..a9aad4e3c --- /dev/null +++ b/java/res/values-ar/donottranslate.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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"> + <!-- The all letters need to be mirrored are found at + http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt --> + <!-- Symbols that are suggested between words --> + <string name="suggested_punctuations">!,?,\\,,:,;,\u0022,(|),)|(,\u0027,-,/,@,_</string> +</resources> diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml index dca73659a..c4aa441d8 100644 --- a/java/res/values-ar/strings.xml +++ b/java/res/values-ar/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"لوحة مفاتيح Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"لوحة مفاتيح Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"إعدادات لوحة مفاتيح Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"خيارات الإرسال"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"تصحيح Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"إعدادات التدقيق الإملائي"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"استخدام بيانات التقريب"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"استخدام خوارزمية تقريب شبيهة بلوحة المفاتيح لإجراء التدقيق الإملائي"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"بحث في أسماء جهات الاتصال"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"يستخدم المدقق الإملائي إدخالات من قائمة جهات الاتصال"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"اهتزاز عند ضغط مفتاح"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"صوت عند الضغط على مفتاح"</string> <string name="popup_on_keypress" msgid="123894815723512944">"انبثاق عند ضغط مفتاح"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : تم الحفظ"</string> <string name="label_go_key" msgid="1635148082137219148">"تنفيذ"</string> <string name="label_next_key" msgid="362972844525672568">"التالي"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"تم"</string> <string name="label_send_key" msgid="2815056534433717444">"إرسال"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"أ ب ج"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"إدخال صوتي"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"وجه مبتسم"</string> <string name="spoken_description_return" msgid="8178083177238315647">"رجوع"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"فاصلة"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"نقطة"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"قوس أيسر"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"قوس أيمن"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"نقطتان"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"فاصلة منقوطة"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"علامة التعجب"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"علامة استفهام"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"علامة الاقتباس المزدوجة"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"علامة الاقتباس المفردة"</string> <string name="spoken_description_dot" msgid="40711082435231673">"نقطة"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"جذر تربيعي"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"باي"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"دلتا"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"علامة تجارية"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"رعاية"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"نجمة"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"جنيه"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"علامة حذف"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"علامة الاقتباس المزدوجة السفلية"</string> <string name="voice_warning_title" msgid="4419354150908395008">"الإدخال الصوتي"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"الإدخال الصوتي غير معتمد حاليًا للغتك، ولكنه يعمل باللغة الإنجليزية."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"يستخدم الإدخال الصوتي خاصية التعرف على الكلام من Google. تنطبق "<a href="http://m.google.com/privacy">"سياسة خصوصية الجوال"</a>"."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"تمكين ملاحظات المستخدم"</string> <string name="prefs_description_log" msgid="5827825607258246003">"المساعدة في تحسين محرر طريقة الإرسال هذا من خلال إرسال إحصاءات الاستخدام وتقارير الأعطال تلقائيًا إلى Google."</string> <string name="keyboard_layout" msgid="8451164783510487501">"مظهر لوحة المفاتيح"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"الألمانية (QWERTY)"</string> <string name="subtype_en_GB" msgid="88170601942311355">"الإنجليزية (المملكة المتحدة)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"الإنجليزية (الولايات المتحدة)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"وضع سهولة الاستخدام"</string> diff --git a/java/res/values-de-rZZ/donottranslate-more-keys.xml b/java/res/values-be/donottranslate-more-keys.xml index e7ec5e152..28264c4ac 100644 --- a/java/res/values-de-rZZ/donottranslate-more-keys.xml +++ b/java/res/values-be/donottranslate-more-keys.xml @@ -18,6 +18,6 @@ */ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="more_keys_for_y">6</string> - <string name="more_keys_for_z"></string> + <string name="keylabel_for_slavic_shcha">ў</string> + <string name="keylabel_for_slavic_i">i</string> </resources> diff --git a/java/res/values-be/strings.xml b/java/res/values-be/strings.xml index 1ed944caf..c0094741c 100644 --- a/java/res/values-be/strings.xml +++ b/java/res/values-be/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Клавіятура Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Клавіятура Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Налады клавіятуры Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Параметры ўводу"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Папраўкі Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Налады праверкі арфаграфіі"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Выкарыстоўвайць дадзеныя аб блізкасці"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Для праверкі арфаграфіі выкарыстоўваць алгарытм блізкасці, падобны на клавіятуру"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Шукаць імёны кантактаў"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Модуль праверкі правапісу выкарыстоўвае запісы са спісу кантактаў"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Вібрацыя пры націску клавіш"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Гук пры націску"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Па націску на клавішы ўсплывае акно"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Захаваныя"</string> <string name="label_go_key" msgid="1635148082137219148">"Пачаць"</string> <string name="label_next_key" msgid="362972844525672568">"Далей"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Гатова"</string> <string name="label_send_key" msgid="2815056534433717444">"Адправіць"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Галасавы ўвод"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Смайлік"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Увод"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Коска"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Кропка"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Адчыняючая дужка"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Дужка, якая зачыняе"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Двукроп\'е"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Кропка з коскай"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Клічнік"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Пытальнік"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Двукоссі"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Паўдвукоссі"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Кропка"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Квадратны корань"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Пі"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Дэльта"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Гандлёвая марка"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Працэнт"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Пазначыць"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Фунт"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Шматкроп\'е"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Нізкія падвойныя двукоссі"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Галасавы ўвод"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Галасавы ўвод пакуль не падтрымліваецца для вашай мовы, але працуе на англійскай мове."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Галасавы набор выкарыстоўвае распазнанне гаворкі Google. Ужываецца "<a href="http://m.google.com/privacy">"палiтыка прыватнасцi для мабiльных прылад"</a>"."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Уключыць зваротную сувязь з карыстальнікамі"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Дапамажыце палепшыць гэты рэдактар метаду ўводу, аўтаматычна адпраўляючы статыстыку выкарыстання і справаздачы аб збоях Google."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Тэма клавіятуры"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Нямецкая QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Англійская (ЗК)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Англійская (ЗША)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Рэжым даследвання выкарыстальнасці"</string> diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml index 30fe132d8..900a7fd88 100644 --- a/java/res/values-bg/strings.xml +++ b/java/res/values-bg/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Клавиатура на Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Клавиатура на Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Настройки на клавиатурата на Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Опции за въвеждане"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Корекция на Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Настройки за проверка на правописа"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Използване на близост"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Проверка на правописа: Използвайте алгоритъм за близост"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Търсене на имена"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"За проверка на правописа се ползват записи от списъка с контакти"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Да вибрира при натискане на клавиш"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Звук при натискане на клавиш"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Изскачащ прозорец при натискане на клавиш"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Запазено"</string> <string name="label_go_key" msgid="1635148082137219148">"Старт"</string> <string name="label_next_key" msgid="362972844525672568">"Напред"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Готово"</string> <string name="label_send_key" msgid="2815056534433717444">"Изпращане"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"АБВ"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Гласово въвеждане"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Усмивка"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Return"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Запетая"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Точка"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Лява кръгла скоба"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Дясна кръгла скоба"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Двоеточие"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Точка и запетая"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Удивителен знак"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Въпросителен знак"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Двойни кавички"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Единични кавички"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Точка"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Корен квадратен"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Пи"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Делта"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Запазена марка"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"По адрес"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Звездичка"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Диез"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Многоточие"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Долни двойни кавички"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Гласово въвеждане"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"За вашия език понастоящем не се поддържа гласово въвеждане, но можете да го използвате на английски."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Гласовото въвеждане използва функцията на Google за разпознаване на говор. В сила е "<a href="http://m.google.com/privacy">"Декларацията за поверителност за мобилни устройства"</a>"."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Активиране на отзивите от потребителите"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Помогнете за подобряването на този редактор за въвеждане чрез автоматично изпращане до Google на статистически данни за употребата и сигнали за сривове."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Тема на клавиатурата"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"немски, „QWERTY“"</string> <string name="subtype_en_GB" msgid="88170601942311355">"английски (Великобритания)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"английски (САЩ)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Режим за изучаване на използваемостта"</string> diff --git a/java/res/values-ca/donottranslate-more-keys.xml b/java/res/values-ca/donottranslate-more-keys.xml index bd9fb7ccd..512a86110 100644 --- a/java/res/values-ca/donottranslate-more-keys.xml +++ b/java/res/values-ca/donottranslate-more-keys.xml @@ -19,10 +19,10 @@ --> <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_e">è,é,ë,ê,ę,ė,ē</string> + <string name="more_keys_for_i">í,ï,ì,î,į,ī</string> + <string name="more_keys_for_o">ò,ó,ö,ô,õ,ø,œ,ō,º</string> + <string name="more_keys_for_u">ú,ü,ù,û,ū</string> <string name="more_keys_for_n">ñ,ń</string> <string name="more_keys_for_c">ç,ć,č</string> <string name="more_keys_for_l">ŀ,ł</string> diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml index a58d8faa9..0fae132a6 100644 --- a/java/res/values-ca/strings.xml +++ b/java/res/values-ca/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Teclat Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Teclat d\'Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Configuració del teclat d\'Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opcions d\'entrada"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Correcció d\'Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Configuració de la correcció ortogràfica"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Utilitza les dades de proximitat"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Utilitza un algorisme de proximitat similar al teclat per comprovar l\'ortografia"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Cerca noms de contactes"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"El corrector ortogràfic utilitza entrades de la llista de cont."</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibra en prémer tecles"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"So en prémer una tecla"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Finestra emergent en prémer un botó"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: desada"</string> <string name="label_go_key" msgid="1635148082137219148">"Vés"</string> <string name="label_next_key" msgid="362972844525672568">"Següent"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Fet"</string> <string name="label_send_key" msgid="2815056534433717444">"Envia"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Entrada de veu"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Cara somrient"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Retorn"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Coma"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Punt"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Parèntesi esquerre"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Parèntesi dret"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Coma"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Punt i coma"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Signe d\'admiració"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Signe d\'interrogació"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Cometes dobles"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Cometes simples"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punt"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Arrel quadrada"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Marca comercial"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Percentatge"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Destaca"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Coixinet"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Punts suspensius"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Cometes angulars"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Entrada de veu"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Actualment, l\'entrada de veu no és compatible amb el vostre idioma, però funciona en anglès."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"L\'entrada de veu utilitza el reconeixement de veu de Google. S\'hi aplica la "<a href="http://m.google.com/privacy">"Política de privadesa de Google per a mòbils"</a>"."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Activa els comentaris de l\'usuari"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Ajuda a millorar aquest editor de mètodes d\'entrada enviant automàticament estadístiques d\'ús i informes de bloqueigs a Google."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Tema del teclat"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"QWERTY alemany"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Anglès (Regne Unit)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Anglès (EUA)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Mode d\'estudi d\'usabilitat"</string> diff --git a/java/res/values-cs/donottranslate-more-keys.xml b/java/res/values-cs/donottranslate-more-keys.xml index 70b3f3ee7..3701adb1b 100644 --- a/java/res/values-cs/donottranslate-more-keys.xml +++ b/java/res/values-cs/donottranslate-more-keys.xml @@ -19,16 +19,16 @@ --> <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_e">é,ě,è,ê,ë,ę,ė,ē</string> + <string name="more_keys_for_i">í,î,ï,ì,į,ī</string> + <string name="more_keys_for_o">ó,ö,ô,ò,õ,œ,ø,ō</string> + <string name="more_keys_for_u">ú,ů,û,ü,ù,ū</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">ý,ÿ</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">6,ž,ź,ż</string> + <string name="more_keys_for_r">ř</string> + <string name="more_keys_for_t">ť</string> + <string name="more_keys_for_z">ž,ź,ż</string> </resources> diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml index d57ccaa28..7c4c31ac4 100644 --- a/java/res/values-cs/strings.xml +++ b/java/res/values-cs/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Klávesnice Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Klávesnice Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Nastavení klávesnice Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Možnosti zadávání textu a dat"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Opravy Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Nastavení kontroly pravopisu"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Použít údaje o blízkosti"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Při kontrole pravopisu uvažovat blízkost písmen na klávesnici"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Vyhledat kontakty"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Kontrola pravopisu používá záznamy z vašeho seznamu kontaktů."</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Při stisku klávesy vibrovat"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Zvuk při stisku klávesy"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Zobrazit znaky při stisku klávesy"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Uloženo"</string> <string name="label_go_key" msgid="1635148082137219148">"Přejít"</string> <string name="label_next_key" msgid="362972844525672568">"Další"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Hotovo"</string> <string name="label_send_key" msgid="2815056534433717444">"Odeslat"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Hlasový vstup"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Smajlík"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Čárka"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Tečka"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Levá závorka"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Pravá závorka"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Dvojtečka"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Středník"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Vykřičník"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Otazník"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Uvozovky"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Apostrof"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Tečka"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Odmocnina"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pí"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Ochranná známka"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Procento"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Hvězdička"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Libra"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Tři tečky"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Uvozovky dole"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Hlasový vstup"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Pro váš jazyk aktuálně není hlasový vstup podporován, ale funguje v angličtině."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Hlasový vstup používá rozpoznávání hlasu Google a vztahují se na něj "<a href="http://m.google.com/privacy">"Zásady ochrany osobních údajů pro mobilní služby"</a>"."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Aktivovat zasílání statistik užívání a zpráv o selhání"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Automatickým zasíláním statistik o užívání editoru zadávání dat a zpráv o jeho selhání do Googlu můžete přispět k vylepšení tohoto nástroje."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Motiv klávesnice"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"němčina (QWERTY)"</string> <string name="subtype_en_GB" msgid="88170601942311355">"angličtina (Spojené království)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"angličtina (USA)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Režim studie použitelnosti"</string> diff --git a/java/res/values-da/donottranslate-more-keys.xml b/java/res/values-da/donottranslate-more-keys.xml index 12c1ebfe1..b1c8d2072 100644 --- a/java/res/values-da/donottranslate-more-keys.xml +++ b/java/res/values-da/donottranslate-more-keys.xml @@ -19,15 +19,16 @@ --> <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_e">é,ë</string> + <string name="more_keys_for_i">í,ï</string> + <string name="more_keys_for_o">ó,ô,ò,õ,œ,ō</string> + <string name="more_keys_for_u">ú,ü,û,ù,ū</string> <string name="more_keys_for_s">ß,ś,š</string> <string name="more_keys_for_n">ñ,ń</string> - <string name="more_keys_for_y">6,ý,ÿ</string> + <string name="more_keys_for_y">ý,ÿ</string> <string name="more_keys_for_d">ð</string> <string name="more_keys_for_l">ł</string> + <string name="keylabel_for_scandinavia_row1_11">å</string> <string name="keylabel_for_scandinavia_row2_10">æ</string> <string name="keylabel_for_scandinavia_row2_11">ø</string> <string name="more_keys_for_scandinavia_row2_10">ä</string> diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml index b91acaa90..bc871e7b7 100644 --- a/java/res/values-da/strings.xml +++ b/java/res/values-da/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Android-tastatur"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android-tastatur (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Android-tastatur-indstillinger"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Indstillinger for input"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Android-rettelse"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Indstillinger for stavekontrol"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Brug nærhedsdata"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Brug en tastaturlignende nærhedsalgoritme til stavekontrol"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Slå kontaktnavne op"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Stavekontrollen bruger poster fra listen over kontaktpersoner"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibration ved tastetryk"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Lyd ved tastetryk"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Pop op ved tastetryk"</string> @@ -64,6 +65,7 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Gemt"</string> <string name="label_go_key" msgid="1635148082137219148">"Gå"</string> <string name="label_next_key" msgid="362972844525672568">"Næste"</string> + <string name="label_previous_key" msgid="1211868118071386787">"Forr."</string> <string name="label_done_key" msgid="2441578748772529288">"Udfør"</string> <string name="label_send_key" msgid="2815056534433717444">"Send"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +90,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Stemmeinput"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Smiley"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Tilbage"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Komma"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Punktum"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Venstre parentes"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Højre parentes"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Kolon"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Semikolon"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Udråbstegn"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Spørgsmålstegn"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Dobbelt anførselstegn"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Enkelt anførselstegn"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punktum"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Kvadratrod"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Varemærke"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"De bedste hilsner"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Stjerne"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Pund"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Ellipse"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Lave dobbelte anførelsestegn"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Stemmeinput"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Stemmeinput understøttes i øjeblikket ikke for dit sprog, men fungerer på engelsk."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Stemmeinput anvender Googles stemmegenkendelse. "<a href="http://m.google.com/privacy">"Fortrolighedspolitikken for mobilenheder"</a>" gælder."</string> @@ -144,7 +127,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Aktiver brugerfeedback"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Vær med til at forbedre denne inputmetode ved at sende anvendelsesstatistikker og rapporter om nedbrud til Google."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Tastaturtema"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Tysk QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Engelsk (Storbritannien)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Engelsk (USA)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Tilstand for brugsstudie"</string> diff --git a/java/res/values-de/donottranslate-more-keys.xml b/java/res/values-de/donottranslate-more-keys.xml index 80aa32ae2..48462c59d 100644 --- a/java/res/values-de/donottranslate-more-keys.xml +++ b/java/res/values-de/donottranslate-more-keys.xml @@ -19,11 +19,9 @@ --> <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_o">9,ö,ô,ò,ó,õ,œ,ø,ō</string> - <string name="more_keys_for_u">7,ü,û,ù,ú,ū</string> + <string name="more_keys_for_e">ė</string> + <string name="more_keys_for_o">ö,ô,ò,ó,õ,œ,ø,ō</string> + <string name="more_keys_for_u">ü,û,ù,ú,ū</string> <string name="more_keys_for_s">ß,ś,š</string> <string name="more_keys_for_n">ñ,ń</string> - <string name="more_keys_for_y"></string> - <string name="more_keys_for_z">6</string> </resources> diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml index d329f3271..da5823a76 100644 --- a/java/res/values-de/strings.xml +++ b/java/res/values-de/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Android-Tastatur"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android-Tastatur (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Android-Tastatureinstellungen"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Eingabeoptionen"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Rechtschreibprüfung für Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Einstellungen für Rechtschreibprüfung"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Näherungsdaten verwenden"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Tastaturähnl. Abstandsalgorith. für Rechtschreibprüfung verwenden"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kontaktnamen prüfen"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Rechtschreibprüfung verwendet Einträge aus Ihrer Kontaktliste."</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Bei Tastendruck vibrieren"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Ton bei Tastendruck"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Pop-up bei Tastendruck"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: gespeichert"</string> <string name="label_go_key" msgid="1635148082137219148">"Los"</string> <string name="label_next_key" msgid="362972844525672568">"Weiter"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Fertig"</string> <string name="label_send_key" msgid="2815056534433717444">"Senden"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Spracheingabe"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Smiley"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Eingabe"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Komma"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Punkt"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Öffnende Klammer"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Schließende Klammer"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Doppelpunkt"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Semikolon"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Ausrufezeichen"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Fragezeichen"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Anführungszeichen"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Einfaches Anführungszeichen"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Aufzählungspunkt"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Quadratwurzel"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Trademark"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"c/o"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Sternchen"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Raute"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Auslassungszeichen"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Anführungszeichen unten"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Spracheingabe"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Spracheingaben werden zurzeit nicht für Ihre Sprache unterstützt, funktionieren jedoch in Englisch."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Die Spracheingabe verwendet die Spracherkennung von Google. Es gelten die "<a href="http://m.google.com/privacy">"Google Mobile-Datenschutzbestimmungen"</a>"."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Nutzer-Feedback aktivieren"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Tragen Sie zur Verbesserung dieses Eingabemethodeneditors bei, indem Sie automatisch Nutzungsstatistiken und Absturzberichte an Google senden."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Tastaturdesign"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Deutsche QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Englisch (Großbritannien)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Englisch (USA)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modus der Studie zur Benutzerfreundlichkeit"</string> diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml index 6fe191ee7..d126edb56 100644 --- a/java/res/values-el/strings.xml +++ b/java/res/values-el/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Πληκτρολόγιο Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Πληκτρολόγιο Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Ρυθμίσεις πληκτρολογίου Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Επιλογές εισόδου"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Διόρθωση Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Ρυθμίσεις ορθογραφικού ελέγχου"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Χρ. δεδ. εγγύτ."</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Χρησ. αλγόρ. εγγύτ. τύπου πληκτρ., για ορθ. έλεγχο"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Αναζήτηση ονομάτων επαφών"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Ο ορθογρ. έλεγχος χρησιμοπ. καταχωρίσεις από τη λίστα επαφών σας"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Δόνηση κατά το πάτημα πλήκτρων"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Ήχος κατά το πάτημα πλήκτρων"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Εμφάνιση με το πάτημα πλήκτρου"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Αποθηκεύτηκε"</string> <string name="label_go_key" msgid="1635148082137219148">"Μετ."</string> <string name="label_next_key" msgid="362972844525672568">"Επόμενο"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Τέλος"</string> <string name="label_send_key" msgid="2815056534433717444">"Αποστολή"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ΑΒΓ"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Μικρόφωνο"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Smiley"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Πλήκτρο Return"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Κόμμα"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Τελεία"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Αριστερή παρένθεση"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Δεξιά παρένθεση"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Άνω και κάτω τελεία"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Ερωτηματικό"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Θαυμαστικό"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Ερωτηματικό"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Διπλά εισαγωγικά"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Μονό εισαγωγικό"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Κουκκίδα"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Τετραγωνική ρίζα"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"πι"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Δέλτα"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Εμπορικό σήμα"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Υπεύθυνος"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Αστερίσκος"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Δίεση"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Αποσιωπητικά"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Χαμηλό διπλό εισαγωγικό"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Φωνητική είσοδος"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Η φωνητική είσοδος δεν υποστηρίζεται αυτή τη στιγμή για τη γλώσσα σας, ωστόσο λειτουργεί στα Αγγλικά."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Οι φωνητικές εντολές χρησιμοποιούν την τεχνολογία αναγνώρισης φωνής της Google. Ισχύει "<a href="http://m.google.com/privacy">"η Πολιτική Απορρήτου για κινητά"</a>"."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Ενεργοποίηση σχολίων χρηστών"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Βοηθήστε μας να βελτιώσουμε αυτό το πρόγραμμα επεξεργασίας μεθόδου εισόδου στέλνοντας αυτόματα στατιστικά στοιχεία και αναφορές σφαλμάτων στην Google."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Θέμα πληκτρολογίου"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Γερμανικά QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Αγγλικά (Η.Β.)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Αγγλικά (Η.Π.Α)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Λειτουργία μελέτης χρηστικότητας"</string> diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml index a7d50860c..bce6a51a5 100644 --- a/java/res/values-en-rGB/strings.xml +++ b/java/res/values-en-rGB/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Android keyboard"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android keyboard (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Android keyboard settings"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Input options"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Android correction"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Spellchecking settings"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Use proximity data"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Use a keyboard-like proximity algorithm for spellchecking"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Look up contact names"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Spell checker uses entries from your contact list"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrate on key-press"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Sound on key-press"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Pop-up on key press"</string> @@ -64,6 +65,7 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Saved"</string> <string name="label_go_key" msgid="1635148082137219148">"Go"</string> <string name="label_next_key" msgid="362972844525672568">"Next"</string> + <string name="label_previous_key" msgid="1211868118071386787">"Prev"</string> <string name="label_done_key" msgid="2441578748772529288">"Done"</string> <string name="label_send_key" msgid="2815056534433717444">"Send"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +90,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Voice input"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Smiley face"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Return"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Comma"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Full stop"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Left parenthesis"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Right parenthesis"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Colon"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Semi-colon"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Exclamation mark"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Question mark"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Double quote"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Single quote"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Dot"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Square root"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Trademark"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Care of"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Star"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Pound"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Ellipsis"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Low double quote"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Voice input"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Voice input is not currently supported for your language, but does work in English."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Voice input uses Google\'s speech recognition. "<a href="http://m.google.com/privacy">"The Mobile Privacy Policy"</a>" applies."</string> @@ -144,7 +127,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Enable user feedback"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Help improve this input method editor by sending usage statistics and crash reports automatically to Google."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Keyboard theme"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"German QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"English (UK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"English (US)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Usability study mode"</string> diff --git a/java/res/values-en/additional-proximitychars.xml b/java/res/values-en/additional-proximitychars.xml new file mode 100644 index 000000000..0e1276796 --- /dev/null +++ b/java/res/values-en/additional-proximitychars.xml @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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-array name="additional_proximitychars"> + <!-- Empty entry terminates the proximity chars array. --> + + <!-- Additional proximity chars for a --> + <item>a</item> + <item>e</item> + <item>i</item> + <item>o</item> + <item>u</item> + <item></item> + <!-- Additional proximity chars for e --> + <item>e</item> + <item>a</item> + <item>i</item> + <item>o</item> + <item>u</item> + <item></item> + <!-- Additional proximity chars for i --> + <item>i</item> + <item>a</item> + <item>e</item> + <item>o</item> + <item>u</item> + <item></item> + <!-- Additional proximity chars for o --> + <item>o</item> + <item>a</item> + <item>e</item> + <item>i</item> + <item>u</item> + <item></item> + <!-- Additional proximity chars for u --> + <item>u</item> + <item>a</item> + <item>e</item> + <item>i</item> + <item>o</item> + <item></item> + </string-array> + +</resources>
\ No newline at end of file diff --git a/java/res/values-en/donottranslate-more-keys.xml b/java/res/values-en/donottranslate-more-keys.xml index bc26c6aa0..9073d3b4f 100644 --- a/java/res/values-en/donottranslate-more-keys.xml +++ b/java/res/values-en/donottranslate-more-keys.xml @@ -19,11 +19,11 @@ --> <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_e">è,é,ê,ë,ē</string> + <string name="more_keys_for_i">î,ï,í,ī,ì</string> + <string name="more_keys_for_o">ô,ö,ò,ó,œ,ø,ō,õ</string> <string name="more_keys_for_s">ß</string> - <string name="more_keys_for_u">7,û,ü,ù,ú,ū</string> + <string name="more_keys_for_u">û,ü,ù,ú,ū</string> <string name="more_keys_for_n">ñ</string> <string name="more_keys_for_c">ç</string> </resources> diff --git a/java/res/values-en/whitelist.xml b/java/res/values-en/whitelist.xml index f929cec23..fd79999bf 100644 --- a/java/res/values-en/whitelist.xml +++ b/java/res/values-en/whitelist.xml @@ -422,6 +422,10 @@ <item>needn\'t</item> <item>255</item> + <item>nit</item> + <item>not</item> + + <item>255</item> <item>oclock</item> <item>o\'clock</item> diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml index 95e309ff7..29df462fb 100644 --- a/java/res/values-es-rUS/strings.xml +++ b/java/res/values-es-rUS/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Teclado de Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Teclado de Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Configuración de teclado de Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opciones de entrada"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Corrector de Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Configuración del corrector ortográfico"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Utilizar datos de prox."</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Utilizar algoritmo de prox. de teclado para corrector ortográfico"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Buscar nombres contactos"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"El corrector ortográfico usa entradas de tu lista de contactos."</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar al pulsar teclas"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Sonar al pulsar las teclas"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Aviso emergente al pulsar tecla"</string> @@ -35,12 +36,12 @@ <string name="misc_category" msgid="6894192814868233453">"Otras opciones"</string> <string name="advanced_settings" msgid="362895144495591463">"Configuración avanzada"</string> <string name="advanced_settings_summary" msgid="5193513161106637254">"Opciones para usuarios expertos"</string> - <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Demora en rechazo de ventana emergente de clave"</string> + <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Retraso en rechazo de alerta de tecla"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sin demora"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predeterminada"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir nombres de contacto"</string> <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Usar nombres de los contactos para sugerencias y correcciones"</string> - <string name="enable_span_insert" msgid="7204653105667167620">"Habilitar correcciones"</string> + <string name="enable_span_insert" msgid="7204653105667167620">"Activar correcciones"</string> <string name="enable_span_insert_summary" msgid="2947317657871394467">"Establecer sugerencias para realizar correcciones"</string> <string name="auto_cap" msgid="1719746674854628252">"Mayúsculas automáticas"</string> <string name="configure_dictionaries_title" msgid="4238652338556902049">"Diccionarios complementarios"</string> @@ -52,7 +53,7 @@ <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Ocultar siempre"</string> <string name="prefs_settings_key" msgid="4623341240804046498">"Mostrar tecla de configuración"</string> <string name="auto_correction" msgid="4979925752001319458">"Corrección automática"</string> - <string name="auto_correction_summary" msgid="5625751551134658006">"La barra espaciadora y puntuación insertan automáticamente las palabras corregidas"</string> + <string name="auto_correction_summary" msgid="5625751551134658006">"La barra espaciadora y las teclas de puntuación insertan automáticamente la palabra corregida"</string> <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Desactivado"</string> <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Moderado"</string> <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Total"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: guardada"</string> <string name="label_go_key" msgid="1635148082137219148">"Ir"</string> <string name="label_next_key" msgid="362972844525672568">"Siguiente"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Hecho"</string> <string name="label_send_key" msgid="2815056534433717444">"Enviar"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Entrada de voz"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Carita sonriente"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Volver"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Coma"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Punto"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Paréntesis de apertura"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Paréntesis de cierre"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Dos puntos"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Punto y coma"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Signo de admiración"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Signo de interrogación"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Comillas dobles"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Comillas simples"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punto"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Raíz cuadrada"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Marca registrada"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"En atención de"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Destacar"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Numeral"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Elipsis"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Comillas bajas"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Entrada por voz"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"La entrada por voz no está admitida en tu idioma, pero sí funciona en inglés."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"La entrada de voz usa el reconocimiento de voz de Google. "<a href="http://m.google.com/privacy">"Se aplica la política de privacidad para"</a>" celulares."</string> @@ -128,7 +112,7 @@ <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Sugerencia:"</b>" La próxima vez intenta decir la puntuación como \"punto\", \"coma\" o \"signo de pregunta\"."</string> <string name="cancel" msgid="6830980399865683324">"Cancelar"</string> <string name="ok" msgid="7898366843681727667">"Aceptar"</string> - <string name="voice_input" msgid="3583258583521397548">"Clave de entrada de voz"</string> + <string name="voice_input" msgid="3583258583521397548">"Tecla de entrada por voz"</string> <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"En el teclado principal"</string> <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"En el teclado de símbolos"</string> <string name="voice_input_modes_off" msgid="3745699748218082014">"Desactivado"</string> @@ -141,10 +125,9 @@ <string name="select_language" msgid="3693815588777926848">"Idiomas de entrada"</string> <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← Tocar de nuevo para guardar"</string> <string name="has_dictionary" msgid="6071847973466625007">"Diccionario disponible"</string> - <string name="prefs_enable_log" msgid="6620424505072963557">"Habilitar los comentarios del usuario"</string> + <string name="prefs_enable_log" msgid="6620424505072963557">"Activar los comentarios del usuario"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Ayuda a mejorar este editor de método de introducción de texto al enviar las estadísticas de uso y los informes de error a Google."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Tema del teclado"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"QWERTY alemán"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Inglés (Reino Unido)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Inglés (EE.UU.)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modo de estudio de usabilidad"</string> diff --git a/java/res/values-es/donottranslate-more-keys.xml b/java/res/values-es/donottranslate-more-keys.xml index d5a8ed19d..429273647 100644 --- a/java/res/values-es/donottranslate-more-keys.xml +++ b/java/res/values-es/donottranslate-more-keys.xml @@ -19,10 +19,10 @@ --> <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_e">é,è,ë,ê,ę,ė,ē</string> + <string name="more_keys_for_i">í,ï,ì,î,į,ī</string> + <string name="more_keys_for_o">ó,ò,ö,ô,õ,ø,œ,ō,º</string> + <string name="more_keys_for_u">ú,ü,ù,û,ū</string> <string name="more_keys_for_n">ñ,ń</string> <string name="more_keys_for_c">ç,ć,č</string> <string name="more_keys_for_punctuation">"\\,,\?,!,¿,¡,:,-,\',\",),(,/,;,+,&,\@"</string> diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml index fcd65e1fc..4e47069f6 100644 --- a/java/res/values-es/strings.xml +++ b/java/res/values-es/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Teclado de Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Teclado Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Ajustes del teclado de Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opciones introducción texto"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Corrector de Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Ajustes del corrector ortográfico"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Usar datos de proximidad"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Usar algoritmo de proximidad de teclado para corregir la ortografía"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Buscar nombres de contactos"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"El corrector ortográfico usa entradas de tu lista de contactos."</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar al pulsar tecla"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Sonido al pulsar tecla"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Pop-up al pulsar tecla"</string> @@ -64,6 +65,7 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: guardada"</string> <string name="label_go_key" msgid="1635148082137219148">"Ir"</string> <string name="label_next_key" msgid="362972844525672568">"Sig."</string> + <string name="label_previous_key" msgid="1211868118071386787">"Anterior"</string> <string name="label_done_key" msgid="2441578748772529288">"Ok"</string> <string name="label_send_key" msgid="2815056534433717444">"Enviar"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +90,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Entrada de voz"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Emoticono"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Tecla Intro"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Coma"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Punto"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Paréntesis de apertura"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Paréntesis de cierre"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Dos puntos"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Punto y coma"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Signo de exclamación"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Signo de interrogación"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Comillas dobles"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Comillas simples"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punto"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Raíz cuadrada"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Marca comercial"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Porcentaje"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Asterisco"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Almohadilla"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Puntos suspensivos"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Comillas dobles bajas"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Introducción de voz"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Actualmente la introducción de voz no está disponible en tu idioma, pero se puede utilizar en inglés."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"La entrada de voz utiliza el reconocimiento de voz de Google. Se aplica la "<a href="http://m.google.com/privacy">"Política de privacidad de Google para móviles"</a>"."</string> @@ -144,7 +127,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Habilitar comentarios de usuarios"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Ayuda a mejorar este editor de método de introducción de texto enviando estadísticas de uso e informes de error a Google."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Tema de teclado"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"QWERTY alemán"</string> <string name="subtype_en_GB" msgid="88170601942311355">"inglés (Reino Unido)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"inglés (EE.UU.)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modo de estudio de usabilidad"</string> 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..bda22fcec --- /dev/null +++ b/java/res/values-et/donottranslate-more-keys.xml @@ -0,0 +1,42 @@ +<?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">ē,è,ė,é,ê,ë,ę,ě</string> + <string name="more_keys_for_i">ī,ì,į,í,î,ï,ı</string> + <string name="more_keys_for_o">ö,õ,ò,ó,ô,œ,ő,ø</string> + <string name="more_keys_for_u">ü,ū,ų,ù,ú,û,ů,ű</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">ý,ÿ</string> + <string name="more_keys_for_d">ď</string> + <string name="more_keys_for_r">ŗ,ř,ŕ</string> + <string name="more_keys_for_t">ţ,ť</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="keylabel_for_scandinavia_row1_11">ü</string> + <string name="keylabel_for_scandinavia_row2_10">ö</string> + <string name="keylabel_for_scandinavia_row2_11">ä</string> + <string name="more_keys_for_scandinavia_row2_10">õ</string> + <string name="more_keys_for_scandinavia_row2_11"></string> +</resources> diff --git a/java/res/values-et/strings.xml b/java/res/values-et/strings.xml index 2c69c99d3..a65bd4a95 100644 --- a/java/res/values-et/strings.xml +++ b/java/res/values-et/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Androidi klaviatuur"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android-klaviatuur (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Androidi klaviatuuriseaded"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Sisestusvalikud"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Androidi parandus"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Õigekirjakontrolli seaded"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Kasuta lähedusandmeid"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Kasuta õigekirjakontrollis klaviatuurisarnast lähedusalgoritmi"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kontakti nimede kontroll."</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Õigekirjakontroll kasutab teie kontaktisikute loendi sissekandeid"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibreeri klahvivajutusel"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Heli klahvivajutusel"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Klahvivajutusel kuva hüpik"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : salvestatud"</string> <string name="label_go_key" msgid="1635148082137219148">"Mine"</string> <string name="label_next_key" msgid="362972844525672568">"Edasi"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Valmis"</string> <string name="label_send_key" msgid="2815056534433717444">"Saada"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Kõnesisend"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Naerunägu"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Tagasi"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Koma"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Punkt"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Vasaksulg"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Paremsulg"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Koolon"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Semikoolon"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Hüüumärk"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Küsimärk"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Jutumärgid"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Üksikjutumärgid"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punkt"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Ruutjuur"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pii"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Kaubamärk"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Vahendaja"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Tärn"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Nael"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Kolmikpunkt"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Alumised jutumärgid"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Kõnesisend"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Kõnesisendit ei toetata praegu teie keeles, kuid see töötab inglise keeles."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Kõnesisend kasutab Google\'i kõnetuvastust. Kehtivad "<a href="http://m.google.com/privacy">"Mobile\'i privaatsuseeskirjad"</a>"."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Luba kasutaja tagasiside"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Saatke Google\'ile automaatselt kasutusstatistikat ja krahhiaruandeid ning aidake seda sisestusmeetodi redigeerijat parandada."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Klaviatuuri teema"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Saksa QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Inglise (UK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Inglise (USA)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Kasutatavuse uurimisrežiim"</string> diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml index 7d8c1e941..9b757505a 100644 --- a/java/res/values-fa/strings.xml +++ b/java/res/values-fa/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"صفحه کلید Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"صفحه کلید (Android (AOSP"</string> <string name="english_ime_settings" msgid="6661589557206947774">"تنظیمات صفحه کلید Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"گزینه های ورودی"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"تصحیح Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"تنظیمات غلط گیری املایی"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"استفاده از دادههای مجاورت"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"استفاده از یک الگوریتم مجاورت مشابه صفحه کلید برای غلط گیری املایی"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"جستجوی نام مخاطبین"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"غلطگیر املا از ورودیهای لیست مخاطبین شما استفاده میکند"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"لرزش با فشار کلید"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"صدا با فشار کلید"</string> <string name="popup_on_keypress" msgid="123894815723512944">"بازشدن با فشار کلید"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : ذخیره شد"</string> <string name="label_go_key" msgid="1635148082137219148">"برو"</string> <string name="label_next_key" msgid="362972844525672568">"بعدی"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"انجام شد"</string> <string name="label_send_key" msgid="2815056534433717444">"ارسال"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -92,26 +95,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"ورودی صدا"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"صورت متبسم"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Return"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"کاما"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"نقطه"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"پرانتز چپ"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"پرانتز راست"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"دو نقطه"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"نقطه ویرگول"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"علامت تعجب"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"علامت سؤال"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"علامت نقل قول"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"علامت نقل قول تکی"</string> <string name="spoken_description_dot" msgid="40711082435231673">"نقطه"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"ریشه دوم"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"پی"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"دلتا"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"علامت تجاری"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"توسط"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"ستاره"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"پوند"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"سه نقطه"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"علامت نقل قول پایین"</string> <string name="voice_warning_title" msgid="4419354150908395008">"ورودی صوتی"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"ورودی صوتی در حال حاضر برای زبان شما پشتیبانی نمی شود اما برای زبان انگلیسی فعال است."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"ورودی صوتی از تشخیص صدای Google استفاده می کند. "<a href="http://m.google.com/privacy">"خط مشی رازداری Mobile "</a>" اعمال می شود."</string> @@ -148,7 +132,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"فعال کردن بازخورد کاربر"</string> <string name="prefs_description_log" msgid="5827825607258246003">"با ارسال خودکار آمارهای کاربرد و گزارش های خرابی به Google، به بهبود این ویرایشگر روش ورودی کمک کنید."</string> <string name="keyboard_layout" msgid="8451164783510487501">"طرح زمینه صفحه کلید"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"QWERTY آلمانی"</string> <string name="subtype_en_GB" msgid="88170601942311355">"انگیسی (UK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"انگیسی (US)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"حالت بررسی قابلیت استفاده"</string> diff --git a/java/res/values-fi/donottranslate-more-keys.xml b/java/res/values-fi/donottranslate-more-keys.xml index df67c69ba..b922fe21d 100644 --- a/java/res/values-fi/donottranslate-more-keys.xml +++ b/java/res/values-fi/donottranslate-more-keys.xml @@ -19,10 +19,11 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="more_keys_for_a">æ,à,á,â,ã,ā</string> - <string name="more_keys_for_o">9,ø,ô,ò,ó,õ,œ,ō</string> - <string name="more_keys_for_u">7,ü</string> + <string name="more_keys_for_o">ø,ô,ò,ó,õ,œ,ō</string> + <string name="more_keys_for_u">ü</string> <string name="more_keys_for_s">š,ß,ś</string> <string name="more_keys_for_z">ž,ź,ż</string> + <string name="keylabel_for_scandinavia_row1_11">å</string> <string name="keylabel_for_scandinavia_row2_10">ö</string> <string name="keylabel_for_scandinavia_row2_11">ä</string> <string name="more_keys_for_scandinavia_row2_10">ø</string> diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml index c77cd8107..c4da3cbf7 100644 --- a/java/res/values-fi/strings.xml +++ b/java/res/values-fi/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Android-näppäimistö"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android-näppäimistö (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Android-näppäimistön asetukset"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Syöttövalinnat"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Android-korjaus"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Oikoluvun asetukset"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Käytä lähestymistietoja"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Käytä näppäimistön kaltaista lähestymisalgoritmia oikolukuun"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Hae kontaktien nimiä"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Oikeinkirjoituksen tarkistus käyttää kontaktiluettelosi tietoja."</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Käytä värinää näppäimiä painettaessa"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Toista ääni näppäimiä painettaessa"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Ponnahdusikkuna painalluksella"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Tallennettu"</string> <string name="label_go_key" msgid="1635148082137219148">"Siirry"</string> <string name="label_next_key" msgid="362972844525672568">"Seur."</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Valmis"</string> <string name="label_send_key" msgid="2815056534433717444">"Lähetä"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Puheohjaus"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Hymiö"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Pilkku"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Piste"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Vasen sulkumerkki"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Oikea sulkumerkki"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Kaksoispiste"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Puolipiste"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Huutomerkki"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Kysymysmerkki"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Lainausmerkki"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Puolilainausmerkki"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Piste"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Neliöjuuri"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pii"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Tavaramerkki"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"C/O"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Tähti"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Punta"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Ellipsi"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Rivinalinen lainausmerkki"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Äänisyöte"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Äänisyötettä ei vielä tueta kielelläsi, mutta voit käyttää sitä englanniksi."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Äänisyöte käyttää Googlen puheentunnistusta. "<a href="http://m.google.com/privacy">"Mobile-tietosuojakäytäntö"</a>" on voimassa."</string> @@ -123,7 +107,7 @@ <string name="voice_server_error" msgid="7807129913977261644">"Palvelinvirhe"</string> <string name="voice_speech_timeout" msgid="8461817525075498795">"Puhetta ei kuulu"</string> <string name="voice_no_match" msgid="4285117547030179174">"Ei vastineita"</string> - <string name="voice_not_installed" msgid="5552450909753842415">"Äänihakua ei asennettu"</string> + <string name="voice_not_installed" msgid="5552450909753842415">"Puhehakua ei asennettu"</string> <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Vihje:"</b>" liu\'uta sormea näppäimistöllä ja puhu"</string> <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Vihje:"</b>" kokeile seuraavalla kerralla puhua välimerkit, kuten \"period\" (piste), \"comma\" (pilkku) tai \"question mark\" (kysymysmerkki)."</string> <string name="cancel" msgid="6830980399865683324">"Peruuta"</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Ota käyttäjäpalaute käyttöön"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Auta parantamaan tätä syöttötavan muokkausohjelmaa lähettämällä automaattisesti käyttötietoja ja kaatumisraportteja Googlelle."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Näppäimistöteema"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"saksa, QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"englanti (Iso-Britannia)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"englanti (Yhdysvallat)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Käytettävyystutkimustila"</string> diff --git a/java/res/values-fr/donottranslate-more-keys.xml b/java/res/values-fr/donottranslate-more-keys.xml index cd6d49bad..0f78e7cd9 100644 --- a/java/res/values-fr/donottranslate-more-keys.xml +++ b/java/res/values-fr/donottranslate-more-keys.xml @@ -18,14 +18,11 @@ */ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="more_keys_for_a">à,â,1,æ,á,ä,ã,å,ā,ª</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_a">à,â,%,æ,á,ä,ã,å,ā,ª</string> + <string name="more_keys_for_e">é,è,ê,ë,%,ę,ė,ē</string> + <string name="more_keys_for_i">î,%,ï,ì,í,į,ī</string> + <string name="more_keys_for_o">ô,œ,%,ö,ò,ó,õ,ø,ō,º</string> + <string name="more_keys_for_u">ù,û,%,ü,ú,ū</string> <string name="more_keys_for_c">ç,ć,č</string> - <string name="more_keys_for_y">6,ÿ</string> - <string name="more_keys_for_q"></string> - <string name="more_keys_for_w"></string> - <string name="more_keys_for_z">2</string> + <string name="more_keys_for_y">%,ÿ</string> </resources> diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml index 7b89edd54..e9536ec35 100644 --- a/java/res/values-fr/strings.xml +++ b/java/res/values-fr/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Clavier Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Clavier Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Paramètres du clavier Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Options de saisie"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Correcteur Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Paramètre du correcteur orthographique"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Utiliser données proximité"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Utiliser algorithme de proximité clavier pour correcteur ortho"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Rechercher noms contacts"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Correcteur orthographique utilise entrées de liste de contacts."</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrer à chaque touche"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Son à chaque touche"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Agrandir les caractères"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : enregistré"</string> <string name="label_go_key" msgid="1635148082137219148">"OK"</string> <string name="label_next_key" msgid="362972844525672568">"Suiv."</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"OK"</string> <string name="label_send_key" msgid="2815056534433717444">"Envoi"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Saisie vocale"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Émoticône"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Entrée"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Virgule"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Point"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Parenthèse gauche"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Parenthèse droite"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Deux-points"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Point-virgule"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Point d\'exclamation"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Point d\'interrogation"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Guillemets doubles"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Apostrophe"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Point"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Racine carrée"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Marque commerciale"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"à l\'attention de"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Étoile"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Dièse"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Ellipse"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Guillemets bas doubles"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Saisie vocale"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"La saisie vocale n\'est pas encore prise en charge pour votre langue, mais elle fonctionne en anglais."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"La saisie vocale fait appel à la reconnaissance vocale de Google. Les "<a href="http://m.google.com/privacy">"Règles de confidentialité Google Mobile"</a>" s\'appliquent."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Autoriser les commentaires des utilisateurs"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Contribuer à l\'amélioration de cet éditeur du mode de saisie grâce à l\'envoi automatique de statistiques d\'utilisation et de rapports d\'incident à Google."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Thème du clavier"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Clavier QWERTY allemand"</string> <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> diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml index de95ab8d7..6b17d6751 100644 --- a/java/res/values-hi/strings.xml +++ b/java/res/values-hi/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Android कीबोर्ड"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android कीबोर्ड (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Android कीबोर्ड सेटिंग"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"इनपुट विकल्प"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Android correction"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"वर्तनी जांच सेटिंग"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"निकटस्थ डेटा उपयोग करें"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"वर्तनी जांचने के लिए कीबोर्ड जैसे निकटस्थ एल्गोरिदम का उपयोग करें"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"संपर्क नामों को खोजें"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"वर्तनी परीक्षक आपकी संपर्क सूची की प्रविष्टियों का उपयोग करता है"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"कुंजी दबाने पर कंपन करता है"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"कुंजी दबाने पर आवाज"</string> <string name="popup_on_keypress" msgid="123894815723512944">"कुंजी दबाने पर पॉपअप दिखाएं"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: सहेजा गया"</string> <string name="label_go_key" msgid="1635148082137219148">"जाएं"</string> <string name="label_next_key" msgid="362972844525672568">"अगला"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"पूर्ण"</string> <string name="label_send_key" msgid="2815056534433717444">"भेजें"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"ध्वनि इनपुट"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"मुस्कुराता चेहरा"</string> <string name="spoken_description_return" msgid="8178083177238315647">"रिटर्न"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"अल्पविराम"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"पूर्णविराम"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"बायां कोष्ठक"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"दायां कोष्ठक"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"अपूर्ण विराम"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"अर्द्धविराम"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"विस्मयादिबोधक चिह्न"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"प्रश्नचिह्न"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"दोहरा उद्धरण"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"एकल उद्धरण"</string> <string name="spoken_description_dot" msgid="40711082435231673">"बिंदु"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"वर्गमूल"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"पाइ"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"डेल्टा"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"ट्रेडमार्क"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"संरक्षक"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"तारा"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"पाउंड"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"पदलोप चिह्न"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"निम्न दोहरा उद्धरण"</string> <string name="voice_warning_title" msgid="4419354150908395008">"ध्वनि इनपुट"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"ध्वनि इनपुट आपकी भाषा के लिए अभी समर्थित नहीं है, पर अंग्रेज़ी में कार्य करता है."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"ध्वनि इनपुट Google की वाक् पहचान का उपयोग करता है. "<a href="http://m.google.com/privacy">"मोबाइल गोपनीयता नीति"</a>" लागू होती है."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"उपयोगकर्ता फ़ीडबैक सक्षम करें"</string> <string name="prefs_description_log" msgid="5827825607258246003">"उपयोग के आंकड़े और क्रैश रिपोर्ट Google को स्वचालित रूप से भेज कर इस इनपुट पद्धति संपादक को बेहतर बनाने में सहायता करें."</string> <string name="keyboard_layout" msgid="8451164783510487501">"कीबोर्ड थीम"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"जर्मन QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"अंग्रेज़ी (यूके)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"अंग्रेज़ी (यूएस)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"उपयोगिता अध्ययन मोड"</string> diff --git a/java/res/values-hr/donottranslate-more-keys.xml b/java/res/values-hr/donottranslate-more-keys.xml index c34e0e646..112c444c3 100644 --- a/java/res/values-hr/donottranslate-more-keys.xml +++ b/java/res/values-hr/donottranslate-more-keys.xml @@ -21,7 +21,7 @@ <string name="more_keys_for_s">š,ś,ß</string> <string name="more_keys_for_n">ñ,ń</string> <string name="more_keys_for_y"></string> - <string name="more_keys_for_z">6,ž,ź,ż</string> + <string name="more_keys_for_z">ž,ź,ż</string> <string name="more_keys_for_c">č,ć,ç</string> <string name="more_keys_for_d">đ</string> </resources> diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml index 30c20b3cc..1d35c613e 100644 --- a/java/res/values-hr/strings.xml +++ b/java/res/values-hr/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Android tipkovnica"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android tipkovnica (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Postavke tipkovnice za Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opcije ulaza"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Ispravak za Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Postavke provjere pravopisa"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Upotreba podataka blizine"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Za prov. pravopisa upotrijebi algoritam blizine kao na tipkovnici"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Potražite imena kontakata"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Provjera pravopisa upotrebljava unose iz vašeg popisa kontakata"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibracija pri pritisku na tipku"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Zvuk pri pritisku tipke"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Povećanja na pritisak tipke"</string> @@ -35,7 +36,7 @@ <string name="misc_category" msgid="6894192814868233453">"Ostale opcije"</string> <string name="advanced_settings" msgid="362895144495591463">"Napredne postavke"</string> <string name="advanced_settings_summary" msgid="5193513161106637254">"Opcije za stručne korisnike"</string> - <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Bez odgode klj. skočnih"</string> + <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Odgoda prikaza tipki"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Bez odgode"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Zadano"</string> <string name="use_contacts_dict" msgid="4435317977804180815">"Predlaži imena kontakata"</string> @@ -52,7 +53,7 @@ <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Uvijek sakrij"</string> <string name="prefs_settings_key" msgid="4623341240804046498">"Prikaži tipku postavki"</string> <string name="auto_correction" msgid="4979925752001319458">"Samoispravak"</string> - <string name="auto_correction_summary" msgid="5625751551134658006">"Razm. i intrp. aut. ispr. kr. rči."</string> + <string name="auto_correction_summary" msgid="5625751551134658006">"Razmak i interpunkcija automatski ispravljaju krive riječi"</string> <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Isključeno"</string> <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Skromno"</string> <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresivno"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Spremljeno"</string> <string name="label_go_key" msgid="1635148082137219148">"Idi"</string> <string name="label_next_key" msgid="362972844525672568">"Dalje"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Gotovo"</string> <string name="label_send_key" msgid="2815056534433717444">"Pošalji"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Glasovni unos"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Smješko"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Zarez"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Točka"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Lijeva zagrada"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Desna zagrada"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Dvotočka"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Točka-zarez"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Uskličnik"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Upitnik"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Dvostruki navodnici"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Jednostruki navodnici"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Točka"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Kvadratni korijen"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Zaštitni znak"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"U ruke"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Zvjezdica"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"funta"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Tri točke"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Donji dvostruki navodnici"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Glasovni ulaz"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Vaš jezik trenutno nije podržan za glasovni unos, ali radi za engleski."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Glasovni unos upotrebljava Googleovo prepoznavanje govora. Primjenjuju se "<a href="http://m.google.com/privacy">"Pravila o privatnosti za uslugu Mobile"</a>"."</string> @@ -132,7 +116,7 @@ <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Na glavnoj tipkovnici"</string> <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Na tipkovnici simb."</string> <string name="voice_input_modes_off" msgid="3745699748218082014">"Isključeno"</string> - <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mik. na gl. tipk."</string> + <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikrofon na gl. tipkovnici"</string> <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mik. na tipk. simb."</string> <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Glas. unos onemog."</string> <string name="selectInputMethod" msgid="315076553378705821">"Odabir ulazne metode"</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Omogući korisničke povratne informacije"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Pomozite u poboljšanju ovog urednika ulazne metode automatskim slanjem statistike upotrebe i padova Googleu."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Tema tipkovnice"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"njemački QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Engleski (UK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Engleski (SAD)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Način studije upotrebljivosti"</string> diff --git a/java/res/values-hu/donottranslate-more-keys.xml b/java/res/values-hu/donottranslate-more-keys.xml index 42b330199..cc23dff48 100644 --- a/java/res/values-hu/donottranslate-more-keys.xml +++ b/java/res/values-hu/donottranslate-more-keys.xml @@ -19,10 +19,8 @@ --> <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_y"></string> - <string name="more_keys_for_z">6</string> + <string name="more_keys_for_e">é,è,ê,ë,ę,ė,ē</string> + <string name="more_keys_for_i">í,î,ï,ì,į,ī</string> + <string name="more_keys_for_o">ó,ö,ő,ô,ò,õ,œ,ø,ō</string> + <string name="more_keys_for_u">ú,ü,ű,û,ù,ū</string> </resources> diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml index 180b6fcf9..de2e812d7 100644 --- a/java/res/values-hu/strings.xml +++ b/java/res/values-hu/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Android-billentyűzet"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android-billentyűzet (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Android billentyűzetbeállítások"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Beviteli beállítások"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Android korrekció"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Helyesírás-ellenőrzés beállításai"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Közelségi adatok haszn."</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Billentyűzetszerű algoritmus a helyesírás-ellenőrzéshez"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Névjegyek keresése"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"A helyesírás-ellenőrző használja a névjegyek bejegyzéseit"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Rezgés billentyű megnyomása esetén"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Hangjelzés billentyű megnyomása esetén"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Legyen nagyobb billentyű lenyomásakor"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : mentve"</string> <string name="label_go_key" msgid="1635148082137219148">"Ugrás"</string> <string name="label_next_key" msgid="362972844525672568">"Tovább"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Kész"</string> <string name="label_send_key" msgid="2815056534433717444">"Küldés"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Hangbevitel"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Mosolygós arc"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Vessző"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Pont"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Nyitó zárójel"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Berekesztő zárójel"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Kettőspont"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Pontosvessző"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Felkiáltójel"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Kérdőjel"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Dupla idézőjel"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Szimpla idézőjel"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Pont"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Négyzetgyök"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Védjegy"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Százalék"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Csillag"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Kettős kereszt"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Kihagyás"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Alsó dupla idézőjel"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Hangbevitel"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"A hangbevitel szolgáltatás jelenleg nem támogatja az Ön nyelvét, ám angolul működik."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"A hangbevitel a Google beszédfelismerő technológiáját használja, amelyre a "<a href="http://m.google.com/privacy">"Mobil adatvédelmi irányelvek"</a>" érvényesek."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Felhasználói visszajelzés engedélyezése"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Segíthet ennek a beviteli módszernek a javításában, ha engedélyezi a használati statisztikák és a hibajelentések elküldését a Google-nak."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Billentyűzettéma"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Német QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"angol (brit)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"angol (amerikai)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Használhatósági teszt"</string> diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml index a023b6477..92b485622 100644 --- a/java/res/values-in/strings.xml +++ b/java/res/values-in/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Keyboard Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Keyboard Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Setelan keyboard Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opsi masukan"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Koreksi android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Setelan pemeriksaan ejaan"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Gunakan data kedekatan"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Gunakan algoritme kedekatan seperti keyboard untuk memeriksa ejaan"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Cari nama kenalan"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Pemeriksa ejaan menggunakan entri dari daftar kenalan Anda"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Getar jika tombol ditekan"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Berbunyi jika tombol ditekan"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Muncul saat tombol ditekan"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Telah disimpan"</string> <string name="label_go_key" msgid="1635148082137219148">"Buka"</string> <string name="label_next_key" msgid="362972844525672568">"Berikutnya"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Selesai"</string> <string name="label_send_key" msgid="2815056534433717444">"Kirimkan"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Masukan suara"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Wajah tersenyum"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Kembali"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Koma"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Titik"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Kurung tutup"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Kurung buka"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Titik Dua"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Titik koma"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Tanda seru"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Tanda tanya"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Tanda petik"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Petik tunggal"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Titik"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Akar pangkat dua"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Merek dagang"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Dengan alamat"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Bintang"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Pon"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Elipsis"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Tanda petik bawah"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Masukan suara"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Masukan suara saat ini tidak didukung untuk bahasa Anda, tetapi bekerja dalam Bahasa Inggris."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Masukan suara menggunakan pengenalan ucapan Google. "<a href="http://m.google.com/privacy">"Kebijakan Privasi Seluler"</a>" berlaku."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Aktifkan umpan balik pengguna"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Bantu tingkatkan metode editor masukan dengan mengirim statistik penggunaan dan laporan kerusakan ke Google secara otomatis."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Tema keyboard"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"QWERTY Jerman"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Inggris (Inggris)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Inggris (AS)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modus studi daya guna"</string> diff --git a/java/res/values-it/donottranslate-more-keys.xml b/java/res/values-it/donottranslate-more-keys.xml index fa1537bec..69659a389 100644 --- a/java/res/values-it/donottranslate-more-keys.xml +++ b/java/res/values-it/donottranslate-more-keys.xml @@ -19,8 +19,8 @@ --> <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_e">è,é,ê,ë,ę,ė,ē</string> + <string name="more_keys_for_i">ì,í,î,ï,į,ī</string> + <string name="more_keys_for_o">ò,ó,ô,ö,õ,œ,ø,ō,º</string> + <string name="more_keys_for_u">ù,ú,û,ü,ū</string> </resources> diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml index 58c0e2c3b..38e622c2c 100644 --- a/java/res/values-it/strings.xml +++ b/java/res/values-it/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Tastiera Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Tastiera Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Impostazioni tastiera Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opzioni inserimento"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Correzione Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Impostazioni di controllo ortografico"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Usa i dati di prossimità"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Usa algoritmo prossimità (come in tastiere) per controllo ortografico"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Cerca in nomi contatti"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"La funzione di controllo ortografico usa voci dell\'elenco contatti"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrazione tasti"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Suono tasti"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Popup sui tasti"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : parola salvata"</string> <string name="label_go_key" msgid="1635148082137219148">"Vai"</string> <string name="label_next_key" msgid="362972844525672568">"Avanti"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Fine"</string> <string name="label_send_key" msgid="2815056534433717444">"Invia"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Input vocale"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Smile"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Invio"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Virgola"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Punto"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Parentesi aperta"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Parentesi chiusa"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Due punti"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Punto e virgola"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Punto esclamativo"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Punto interrogativo"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Virgolette doppie"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Virgolette semplici"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Pallino"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Radice quadrata"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi greco"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Marchio commerciale"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Presso"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Asterisco"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Cancelletto"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Ellissi"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Virgolette doppie basse"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Comandi vocali"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"I comandi vocali non sono attualmente supportati per la tua lingua ma funzionano in inglese."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"L\'input vocale utilizza il riconoscimento vocale di Google. Sono valide le "<a href="http://m.google.com/privacy">"norme sulla privacy di Google Mobile"</a>"."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Attiva commenti degli utenti"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Aiuta a migliorare l\'editor del metodo di inserimento inviando automaticamente a Google statistiche sull\'utilizzo e segnalazioni sugli arresti anomali."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Tema della tastiera"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"QWERTY tedesca"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Inglese (UK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Inglese (USA)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modalità Studio sull\'usabilità"</string> diff --git a/java/res/values-iw/donottranslate-more-keys.xml b/java/res/values-iw/donottranslate-more-keys.xml index 829486f7b..f44ff2123 100644 --- a/java/res/values-iw/donottranslate-more-keys.xml +++ b/java/res/values-iw/donottranslate-more-keys.xml @@ -20,4 +20,41 @@ <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="more_keys_for_star">★</string> <string name="more_keys_for_plus">±,﬩</string> + <!-- The all letters need to be mirrored are found at + http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt --> + <integer name="keycode_for_left_parenthesis">0x0029</integer> + <integer name="keycode_for_right_parenthesis">0x0028</integer> + <string name="more_keys_for_left_parenthesis">[|],{|},<|></string> + <string name="more_keys_for_right_parenthesis">]|[,}|{,>|<</string> + <integer name="keycode_for_less_than">0x003e</integer> + <integer name="keycode_for_greater_than">0x003c</integer> + <!-- \u2264: LESS-THAN OR EQUAL TO + \u2265: GREATER-THAN EQUAL TO + \u00ab: LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + \u00bb: RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + \u2039: SINGLE LEFT-POINTING ANGLE QUOTATION MARK + \u203a: SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + The following characters don't need BIDI mirroring. + \u2018: LEFT SINGLE QUOTATION MARK + \u2019: RIGHT SINGLE QUOTATION MARK + \u201a: SINGLE LOW-9 QUOTATION MARK + \u201b: SINGLE HIGH-REVERSED-9 QUOTATION MARK + \u201c: LEFT DOUBLE QUOTATION MARK + \u201d: RIGHT DOUBLE QUOTATION MARK + \u201e: DOUBLE LOW-9 QUOTATION MARK + \u201f: DOUBLE HIGH-REVERSED-9 QUOTATION MARK --> + <string name="more_keys_for_less_than">\u2264|\u2265,\u00ab|\u00bb,\u2039|\u203a</string> + <string name="more_keys_for_greater_than">\u2265|\u2264,\u00bb|\u00ab,\u203a|\u2039</string> + <integer name="keycode_for_left_square_bracket">0x005d</integer> + <integer name="keycode_for_right_square_bracket">0x005b</integer> + <integer name="keycode_for_left_curly_bracket">0x007d</integer> + <integer name="keycode_for_right_curly_bracket">0x007b</integer> + <!-- Note: Neither DroidSans nor Roboto have a glyph for DOUBLE HIGH-REVERSED-9 QUOTATION MARK. --> + <!-- <string name="more_keys_for_double_quote">\u201c,\u201d,\u201e,\u201f,\u00ab,\u00bb</string> --> + <!-- The 4-more keys will be displayed in order of "3,1,2,4". --> + <string name="more_keys_for_double_quote">\u201d,\u00ab|\u00bb,\u201c,\u00bb|\u00ab</string> + <!-- Note: Neither DroidSans nor Roboto have a glyph for DOUBLE HIGH-REVERSED-9 QUOTATION MARK. --> + <!-- <string name="more_keys_for_tablet_double_quote">\u201c,\u201d,\u201e,\u201f,\u00ab,\u00bb,\u2018,\u2019,\u201a,\u201b</string> --> + <!-- The 8-more keys with maxMoreKeysColumn=4 will be displayed in order of "3,1,2,4|7,5,6,8". --> + <string name="more_keys_for_tablet_double_quote">\u201d,\u00ab|\u00bb,\u201c,\u00bb|\u00ab,\u2019,\u201a,\u2018,\u201b</string> </resources> diff --git a/java/res/values-iw/donottranslate.xml b/java/res/values-iw/donottranslate.xml new file mode 100644 index 000000000..a9aad4e3c --- /dev/null +++ b/java/res/values-iw/donottranslate.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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"> + <!-- The all letters need to be mirrored are found at + http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt --> + <!-- Symbols that are suggested between words --> + <string name="suggested_punctuations">!,?,\\,,:,;,\u0022,(|),)|(,\u0027,-,/,@,_</string> +</resources> diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml index 292517c68..9aeaffd89 100644 --- a/java/res/values-iw/strings.xml +++ b/java/res/values-iw/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"מקלדת Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"מקלדת Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"הגדרות מקלדת של Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"אפשרויות קלט"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"תיקון Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"הגדרות בדיקת איות"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"שימוש בנתוני הקירבה"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"השתמש באלגוריתם קירבה דמוי-מקלדת עבור בדיקת איות"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"חפש שמות של אנשי קשר"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"בודק האיות משתמש בערכים מרשימת אנשי הקשר שלך"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"רטט בלחיצה על מקשים"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"צלילים בעת לחיצה על מקשים"</string> <string name="popup_on_keypress" msgid="123894815723512944">"חלון קופץ בלחיצה על מקש"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : נשמרה"</string> <string name="label_go_key" msgid="1635148082137219148">"בצע"</string> <string name="label_next_key" msgid="362972844525672568">"הבא"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"סיום"</string> <string name="label_send_key" msgid="2815056534433717444">"שלח"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"אבג"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"קלט קולי"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"פרצוף סמיילי"</string> <string name="spoken_description_return" msgid="8178083177238315647">"חזור"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"פסיק"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"נקודה"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"סוגריים שמאליים"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"סוגריים ימניים"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"נקודתיים"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"נקודה פסיק"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"סימן קריאה"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"סימן שאלה"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"מרכאות כפולות"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"גרש בודד"</string> <string name="spoken_description_dot" msgid="40711082435231673">"נקודה"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"שורש ריבועי"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"פאי"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"דלתה"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"סימן מסחרי"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"לכבוד"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"כוכב"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"סולמית"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"שלוש נקודות"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"מרכאות כפולות תחתונות"</string> <string name="voice_warning_title" msgid="4419354150908395008">"קלט קולי"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"קלט קולי אינו נתמך בשלב זה בשפתך, אך הוא פועל באנגלית."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"קלט קולי משתמש בזיהוי דיבור של Google. "<a href="http://m.google.com/privacy">"מדיניות הפרטיות של \'Google לנייד\'"</a>" חלה במקרה זה."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"הפוך משוב ממשתמשים לפעיל"</string> <string name="prefs_description_log" msgid="5827825607258246003">"עזור לשפר את עורך שיטת הקלט על ידי שליחה אוטומטית של סטטיסטיקת שימוש ודוחות קריסת מחשב ל-Google."</string> <string name="keyboard_layout" msgid="8451164783510487501">"עיצוב מקלדת"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"מקלדת QWERTY גרמנית"</string> <string name="subtype_en_GB" msgid="88170601942311355">"אנגלית (בריטניה)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"אנגלית (ארה\"ב)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"מצב מחקר שימושיות"</string> diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml index 540bb4688..f684e2131 100644 --- a/java/res/values-ja/strings.xml +++ b/java/res/values-ja/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Androidキーボード"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Androidキーボード(AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Androidキーボードの設定"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"入力オプション"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Androidスペルチェッカー"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"スペルチェックの設定"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"近接データを使用"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"スペルチェックでキーボードと同じような近接アルゴリズムを使用する"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"連絡先名の検索"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"スペルチェッカーでは連絡先リストのエントリを使用します"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"キー操作バイブ"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"キー操作音"</string> <string name="popup_on_keypress" msgid="123894815723512944">"キー押下時ポップアップ"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:保存しました"</string> <string name="label_go_key" msgid="1635148082137219148">"実行"</string> <string name="label_next_key" msgid="362972844525672568">"次へ"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"完了"</string> <string name="label_send_key" msgid="2815056534433717444">"送信"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"音声入力"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"顔文字"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"カンマ"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"ピリオド"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"左かっこ"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"右かっこ"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"コロン"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"セミコロン"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"感嘆符"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"疑問符"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"二重引用符"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"単一引用符"</string> <string name="spoken_description_dot" msgid="40711082435231673">"中点"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"平方根"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"円周率記号"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"デルタ"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"商標記号"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"宛名記号"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"アスタリスク"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"ナンバー記号"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"省略記号"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"下付き二重引用符"</string> <string name="voice_warning_title" msgid="4419354150908395008">"音声入力"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"音声入力は現在英語には対応していますが、日本語には対応していません。"</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"音声入力ではGoogleの音声認識技術を利用します。"<a href="http://m.google.com/privacy">"モバイルプライバシーポリシー"</a>"が適用されます。"</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"ユーザーフィードバックを有効にする"</string> <string name="prefs_description_log" msgid="5827825607258246003">"IMEの機能向上のため、使用統計状況やクラッシュレポートをGoogleに自動送信します。"</string> <string name="keyboard_layout" msgid="8451164783510487501">"キーボードのテーマ"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"ドイツ語QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"英語(英国)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"英語(米国)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"使いやすさの研究モード"</string> diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml index bc2b6289c..56705953c 100644 --- a/java/res/values-ko/strings.xml +++ b/java/res/values-ko/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Android 키보드"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android 키보드(AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Android 키보드 설정"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"입력 옵션"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Android 교정"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"맞춤법 검사 설정"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"근접 데이터 사용"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"맞춤법 검사에 대해 키보드와 유사한 근접 알고리즘 사용"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"연락처 이름 조회"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"맞춤법 검사기가 주소록의 항목을 사용합니다."</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"키를 누를 때 진동 발생"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"키를 누를 때 소리 발생"</string> <string name="popup_on_keypress" msgid="123894815723512944">"키를 누를 때 팝업"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: 저장됨"</string> <string name="label_go_key" msgid="1635148082137219148">"이동"</string> <string name="label_next_key" msgid="362972844525672568">"다음"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"완료"</string> <string name="label_send_key" msgid="2815056534433717444">"전송"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"음성 입력"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"웃는 얼굴"</string> <string name="spoken_description_return" msgid="8178083177238315647">"리턴 키"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"쉼표"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"마침표"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"왼쪽 괄호"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"오른쪽 괄호"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"콜론"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"세미콜론"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"느낌표"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"물음표"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"큰따옴표"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"작은따옴표"</string> <string name="spoken_description_dot" msgid="40711082435231673">"점"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"제곱근"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"파이"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"델타"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"상표(™)"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"퍼센트 키"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"별표"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"파운드"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"생략 부호"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"아래쪽 큰따옴표"</string> <string name="voice_warning_title" msgid="4419354150908395008">"음성 입력"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"음성 입력은 현재 자국어로 지원되지 않으며 영어로 작동됩니다."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"음성 입력에서는 Google의 음성 인식 기능을 사용합니다. "<a href="http://m.google.com/privacy">"모바일 개인정보취급방침"</a>"이 적용됩니다."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"사용자 의견 사용"</string> <string name="prefs_description_log" msgid="5827825607258246003">"사용 통계 및 충돌 보고서를 Google에 자동으로 전송하여 입력 방법 편집기의 개선에 도움을 줍니다."</string> <string name="keyboard_layout" msgid="8451164783510487501">"키보드 테마"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"독일어 QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"영어(영국)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"영어(미국)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"가용성 연구 모드"</string> diff --git a/java/res/values-fr-rCA/donottranslate-more-keys.xml b/java/res/values-ky/donottranslate-more-keys.xml index 80e9d9346..44720aa7f 100644 --- a/java/res/values-fr-rCA/donottranslate-more-keys.xml +++ b/java/res/values-ky/donottranslate-more-keys.xml @@ -18,8 +18,7 @@ */ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="more_keys_for_a">à,â,æ,á,ä,ã,å,ā,ª</string> - <string name="more_keys_for_q">1</string> - <string name="more_keys_for_w">2</string> - <string name="more_keys_for_z"></string> + <string name="more_keys_for_slavic_u">ү</string> + <string name="more_keys_for_slavic_en">ң</string> + <string name="more_keys_for_slavic_o">ө</string> </resources> diff --git a/java/res/values-land/dimens.xml b/java/res/values-land/dimens.xml index 4a5c5a44c..f9cce839a 100644 --- a/java/res/values-land/dimens.xml +++ b/java/res/values-land/dimens.xml @@ -53,6 +53,7 @@ <fraction name="key_hint_label_ratio">52%</fraction> <fraction name="key_uppercase_letter_ratio">40%</fraction> <fraction name="key_preview_text_ratio">90%</fraction> + <fraction name="spacebar_text_ratio">40.000%</fraction> <dimen name="key_preview_offset">0.08in</dimen> <dimen name="key_preview_offset_ics">0.01in</dimen> @@ -65,7 +66,7 @@ <dimen name="key_preview_backing_height">72dip</dimen> <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. --> <!-- popup_key_height x 1.2 --> - <dimen name="mini_keyboard_slide_allowance">0.336in</dimen> + <dimen name="more_keys_keyboard_slide_allowance">0.336in</dimen> <!-- popup_key_height x -1.0 --> - <dimen name="mini_keyboard_vertical_correction">-0.280in</dimen> + <dimen name="more_keys_keyboard_vertical_correction">-0.280in</dimen> </resources> diff --git a/java/res/values-lt/donottranslate-more-keys.xml b/java/res/values-lt/donottranslate-more-keys.xml index 6b81e4509..fc6c84b2d 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">ė,ę,ē,è,é,ê,ë,ě</string> + <string name="more_keys_for_i">į,ī,ì,í,î,ï,ı</string> + <string name="more_keys_for_o">ö,õ,ò,ó,ô,œ,ő,ø</string> + <string name="more_keys_for_u">ū,ų,ü,ū,ù,ú,û,ů,ű</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">ý,ÿ</string> + <string name="more_keys_for_d">ď</string> + <string name="more_keys_for_r">ŗ,ř,ŕ</string> + <string name="more_keys_for_t">ţ,ť</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-lt/strings.xml b/java/res/values-lt/strings.xml index 6263f6706..93b52b530 100644 --- a/java/res/values-lt/strings.xml +++ b/java/res/values-lt/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"„Android“ klaviatūra"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"„Android“ klaviatūra (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"„Android“ klaviatūros nustatymai"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Įvesties parinktys"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"„Android“ korekcijos"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Rašybos tikrinimo nustatymai"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Naudoti artimumo duomenis"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Naudokite klaviatūros tipo artimumo algoritmą rašybai patikrinti"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kontaktų vardų paieška"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Rašybos tikrinimo progr. naudoja įrašus, esančius kontaktų sąraše"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibruoti, kai paspaudžiami klavišai"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Klavišo paspaudimo garsas"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Iššoka paspaudus klavišą"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: išsaugota"</string> <string name="label_go_key" msgid="1635148082137219148">"Pradėti"</string> <string name="label_next_key" msgid="362972844525672568">"Kitas"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Atlikta"</string> <string name="label_send_key" msgid="2815056534433717444">"Siųsti"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Įvestis balsu"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Šypsenėlė"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Grįžti"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Kablelis"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Taškas"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Kairysis skliaustas"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Dešinysis skliaustas"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Dvitaškis"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Kabliataškis"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Šauktukas"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Klaustukas"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Dvigubos kabutės"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Viengubos kabutės"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Taškas"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Kvadratinė šaknis"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Prekės ženklas"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Perduoti"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Pažymėti žvaigždute"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Svaras"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Daugtaškis"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Apatinės dvigubos kabutės"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Balso įvestis"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Šiuo metu balso įvestis jūsų kompiuteryje nepalaikoma, bet ji veikia anglų k."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Balso įvesčiai naudojamas „Google“ kalbos atpažinimas. Taikoma "<a href="http://m.google.com/privacy">"privatumo politika mobiliesiems"</a>"."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Įgalinti naudotojų atsiliepimus"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Padėkite patobulinti šią įvesties metodo redagavimo programą automatiškai „Google“ siųsdami naudojimo statistiką ir strigčių ataskaitas."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Klaviatūros tema"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Vokiška QWERTY klaviatūra"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Anglų k. (JK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Anglų k. (JAV)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Tinkamumo tyrimo režimas"</string> diff --git a/java/res/values-lv/donottranslate-more-keys.xml b/java/res/values-lv/donottranslate-more-keys.xml index 77e1c26a0..3b937dfe3 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">ē,ė,è,é,ê,ë,ę,ě</string> + <string name="more_keys_for_i">ī,į,ì,í,î,ï,ı</string> + <string name="more_keys_for_o">ò,ó,ô,õ,ö,œ,ő,ø</string> + <string name="more_keys_for_u">ū,ų,ù,ú,û,ü,ů,ű</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">ý,ÿ</string> + <string name="more_keys_for_d">ď</string> + <string name="more_keys_for_r">ŗ,ř,ŕ</string> + <string name="more_keys_for_t">ţ,ť</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-lv/strings.xml b/java/res/values-lv/strings.xml index af01d92f6..6fc1d996e 100644 --- a/java/res/values-lv/strings.xml +++ b/java/res/values-lv/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Android tastatūra"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android tastatūra (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Android tastatūras iestatījumi"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Ievades opcijas"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Android korekcija"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Pareizrakstības pārbaudes iestatījumi"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Tuvuma datu izmantošana"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Pareizrakstības pārbaudei izmantojiet tastatūrai līdzīgu tuvuma algoritmu."</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Meklēt kontaktp. vārdus"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Pareizrakst. pārbaudītājs lieto ierakstus no kontaktp. saraksta."</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrēt, nospiežot taustiņu"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Skaņa, nospiežot taustiņu"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Nospiežot taustiņu, parādīt uznirstošo izvēlni"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: saglabāts"</string> <string name="label_go_key" msgid="1635148082137219148">"Sākt"</string> <string name="label_next_key" msgid="362972844525672568">"Tālāk"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Gatavs"</string> <string name="label_send_key" msgid="2815056534433717444">"Sūtīt"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Balss ievade"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Smaidoša seja"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Ievadīšanas taustiņš"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Komats"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Punkts"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Kreisā iekava"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Labā iekava"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Kols"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Semikols"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Izsaukuma zīme"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Jautājuma zīme"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Pēdiņas"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Vienpēdiņas"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punkts"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Kvadrātsakne"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pī"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Preču zīme"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"c/o"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Zvaigznīte"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Cipara simbols"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Daudzpunkte"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Apakšējās pēdiņas"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Balss ievade"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Balss ievade jūsu valodā pašlaik netiek atbalstīta, taču tā ir pieejama angļu valodā."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Balss ievadei tiek izmantota Google runas atpazīšanas funkcija. Uz šīs funkcijas lietošanu attiecas "<a href="http://m.google.com/privacy">"mobilo sakaru ierīču lietošanas konfidencialitātes politika"</a>"."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Iespējot lietotāju atsauksmes"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Palīdziet uzlabot šo ievades metodes redaktoru, automātiski nosūtot lietojuma statistiku un pārskatus par avārijām uzņēmumam Google."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Tastatūras motīvs"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Vācu valodas QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Angļu valoda (Lielbritānija)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Angļu valoda (ASV)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Lietojamības izpētes režīms"</string> diff --git a/java/res/values-ms/strings.xml b/java/res/values-ms/strings.xml index d6bf559e7..e75cc80e3 100644 --- a/java/res/values-ms/strings.xml +++ b/java/res/values-ms/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Papan kekunci Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Papan kekunci Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Tetapan papan kekunci Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Pilihan input"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Pembetulan Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Tetapan penyemakan ejaan"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Gunakan data kehampiran"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Gunakan algoritma kehampiran ala papan kekunci untuk pemeriksaan ejaan"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Cari nama kenalan"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Penyemak ejaan menggunakan entri dari senarai kenalan anda"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Getar pada tekanan kekunci"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Bunyi pada tekanan kekunci"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Pop timbul pada tekanan kunci"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Disimpan"</string> <string name="label_go_key" msgid="1635148082137219148">"Pergi"</string> <string name="label_next_key" msgid="362972844525672568">"Seterusnya"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Selesai"</string> <string name="label_send_key" msgid="2815056534433717444">"Hantar"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Input suara"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Muka senyum"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Return"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Koma"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Tempoh"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Tanda kurung kiri"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Tanda kurung kanan"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Titik bertindih"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Koma bertitik"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Tanda seru"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Tanda soal"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Tanda petikan berganda"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Tanda petikan tunggal"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Titik"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Punca kuasa dua"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Tanda dagangan"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Dengan alamat"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Bintang"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Paun"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Elipsis"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Tanda petikan berganda rendah"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Input suara"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Input suara tidak disokong untuk bahasa anda pada masa ini tetapi ia berfungsi dalam bahasa Inggeris."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Input suara menggunakan pengecaman pertuturan Google. "<a href="http://m.google.com/privacy">"Dasar Privasi Mudah Alih"</a>" digunakan."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Dayakan maklum balas pengguna"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Bantu memperbaik editor input ini dengan menghantar statistik penggunaan dan laporan runtuhan kepada Google."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Tema papan kekunci"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"QWERTY Bahasa Jerman"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Bahasa Inggeris (UK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Bahasa Inggeris (AS)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Mod kajian kebolehgunaan"</string> diff --git a/java/res/values-nb/donottranslate-more-keys.xml b/java/res/values-nb/donottranslate-more-keys.xml index b98341c6a..cf6e4d1ce 100644 --- a/java/res/values-nb/donottranslate-more-keys.xml +++ b/java/res/values-nb/donottranslate-more-keys.xml @@ -19,9 +19,10 @@ --> <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_o">9,ô,ò,ó,ö,õ,œ,ō</string> - <string name="more_keys_for_u">7,ü,û,ù,ú,ū</string> + <string name="more_keys_for_e">é,è,ê,ë,ę,ė,ē</string> + <string name="more_keys_for_o">ô,ò,ó,ö,õ,œ,ō</string> + <string name="more_keys_for_u">ü,û,ù,ú,ū</string> + <string name="keylabel_for_scandinavia_row1_11">å</string> <string name="keylabel_for_scandinavia_row2_10">ø</string> <string name="keylabel_for_scandinavia_row2_11">æ</string> <string name="more_keys_for_scandinavia_row2_10">ö</string> diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml index acd636bdd..1141e3314 100644 --- a/java/res/values-nb/strings.xml +++ b/java/res/values-nb/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Skjermtastatur"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android-tastatur (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Innstillinger for skjermtastatur"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Inndataalternativer"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Android-stavekontroll"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Innstillinger for stavekontroll"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Bruk nærhetsdata"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Bruk en tastaturlignende algoritme til stavekontroll"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Slå opp kontaktnavn"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Stavekontrollen bruker oppføringer fra kontaktlisten din"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrer ved tastetrykk"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Lyd ved tastetrykk"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Hurtigvindu ved tastetrykk"</string> @@ -64,6 +65,7 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Lagret"</string> <string name="label_go_key" msgid="1635148082137219148">"Gå"</string> <string name="label_next_key" msgid="362972844525672568">"Neste"</string> + <string name="label_previous_key" msgid="1211868118071386787">"Tidl."</string> <string name="label_done_key" msgid="2441578748772529288">"Utfør"</string> <string name="label_send_key" msgid="2815056534433717444">"Send"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +90,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Taleinndata"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Smilefjes"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Return"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Komma"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Punktum"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Venstre parentes"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Høyre parentes"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Kolon"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Semikolon"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Utropstegn"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Spørsmålstegn"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Dobbelt anførselstegn"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Enkelt anførselstegn"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Prikk"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Kvadratrot"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Varemerke"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"c/o"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Stjerne"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Firkant"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Ellipse"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Lavt dobbelt anførselstegn"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Stemmedata"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Stemmedata håndteres foreløpig ikke på ditt språk, men fungerer på engelsk."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Google Voice bruker Googles talegjenkjenning. "<a href="http://m.google.com/privacy">"Personvernreglene for mobil"</a>" gjelder."</string> @@ -144,7 +127,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Aktiver brukertilbakemelding"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Ved å sende bruksstatistikk og programstopprapporter til Google automatisk, hjelper du oss med å gjøre redigeringsfunksjonen for denne inndatametoden enda bedre."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Tastaturtema"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Tysk QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Engelsk (Storbritannia)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Engelsk (USA)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Nyttighetsmodus"</string> diff --git a/java/res/values-nl/donottranslate-more-keys.xml b/java/res/values-nl/donottranslate-more-keys.xml index 49cc41964..ac03872f3 100644 --- a/java/res/values-nl/donottranslate-more-keys.xml +++ b/java/res/values-nl/donottranslate-more-keys.xml @@ -19,9 +19,9 @@ --> <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_e">é,ë,ê,è,ę,ė,ē</string> + <string name="more_keys_for_i">í,ï,ì,î,į,ī</string> + <string name="more_keys_for_o">ó,ö,ô,ò,õ,œ,ø,ō</string> + <string name="more_keys_for_u">ú,ü,û,ù,ū</string> <string name="more_keys_for_n">ñ,ń</string> </resources> diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml index 7f0ff7eaf..6da587a73 100644 --- a/java/res/values-nl/strings.xml +++ b/java/res/values-nl/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Android-toetsenbord"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android-toetsenbord (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Instellingen voor Android-toetsenbord"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Invoeropties"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Android-spellingcontrole"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Instellingen voor spellingcontrole"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Nabije toetsinfo gebr."</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Algoritme voor nabije toetsen gebruiken voor spellingcontrole"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Contactnamen opzoeken"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"De spellingcontrole gebruikt items uit uw contactenlijst"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Trillen bij toetsaanslag"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Geluid bij toetsaanslag"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Pop-up bij toetsaanslag"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: opgeslagen"</string> <string name="label_go_key" msgid="1635148082137219148">"Start"</string> <string name="label_next_key" msgid="362972844525672568">"Verder"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Gereed"</string> <string name="label_send_key" msgid="2815056534433717444">"Zenden"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Spraakinvoer"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Smiley-gezichtje"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Return"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Komma"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Punt"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Linkerhaakje"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Rechterhaakje"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Dubbele punt"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Puntkomma"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Uitroepteken"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Vraagteken"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Dubbele aanhalingstekens"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Enkel aanhalingsteken"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Stip"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Vierkantswortel"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Handelsmerk"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Ten attentie van"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Ster"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Hekje"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Weglatingsteken"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Lage dubbele aanhalingstekens"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Spraakinvoer"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Spraakinvoer wordt momenteel niet ondersteund in uw taal, maar is wel beschikbaar in het Engels."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Spraakinvoer maakt gebruik van de spraakherkenning van Google. Het "<a href="http://m.google.com/privacy">"Privacybeleid van Google Mobile"</a>" is van toepassing."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Gebruikersfeedback inschakelen."</string> <string name="prefs_description_log" msgid="5827825607258246003">"Help deze invoermethode te verbeteren door automatisch gebruiksstatistieken en crashmeldingen naar Google te verzenden."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Toetsenbordthema"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Duits QWERTY-toetsenbord"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Engels (GB)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Engels (VS)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modus voor gebruiksvriendelijkheidsonderzoek"</string> diff --git a/java/res/values-pl/donottranslate-more-keys.xml b/java/res/values-pl/donottranslate-more-keys.xml index 18e149991..84e74e849 100644 --- a/java/res/values-pl/donottranslate-more-keys.xml +++ b/java/res/values-pl/donottranslate-more-keys.xml @@ -19,8 +19,8 @@ --> <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_o">9,ó,ö,ô,ò,õ,œ,ø,ō</string> + <string name="more_keys_for_e">ę,è,é,ê,ë,ė,ē</string> + <string name="more_keys_for_o">ó,ö,ô,ò,õ,œ,ø,ō</string> <string name="more_keys_for_s">ś,ß,š</string> <string name="more_keys_for_n">ń,ñ</string> <string name="more_keys_for_c">ć,ç,č</string> diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml index a9a6a76b6..cda725bc3 100644 --- a/java/res/values-pl/strings.xml +++ b/java/res/values-pl/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Klawiatura Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Klawiatura Androida (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Ustawienia klawiatury Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opcje wprowadzania"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Korekta Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Ustawienia sprawdzania pisowni"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Użyj danych o klawiszach"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Przy sprawdzaniu pisowni używaj algorytmu uwzględniającego położenie klawiszy na klawiaturze"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Przeszukaj nazwy kontaktów"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Sprawdzanie pisowni bierze pod uwagę wpisy z listy kontaktów."</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Wibracja przy naciśnięciu"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Dźwięk przy naciśnięciu"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Powiększ po naciśnięciu"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Zapisano"</string> <string name="label_go_key" msgid="1635148082137219148">"OK"</string> <string name="label_next_key" msgid="362972844525672568">"Dalej"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"OK"</string> <string name="label_send_key" msgid="2815056534433717444">"Wyślij"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,29 +91,10 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Wprowadzanie głosowe"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Uśmiechnięta buźka"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Przecinek"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Kropka"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Lewy nawias"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Prawy nawias"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Dwukropek"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Średnik"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Wykrzyknik"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Pytajnik"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Cudzysłów podwójny"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Cudzysłów pojedynczy"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punkt"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Pierwiastek kwadratowy"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Znak towarowy"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Znak „przez grzeczność”"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Gwiazdka"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Krzyżyk"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Wielokropek"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Cudzysłów podwójny dolny"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Wprowadzanie głosowe"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Wprowadzanie głosowe obecnie nie jest obsługiwane w Twoim języku, ale działa w języku angielskim."</string> - <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Funkcja wprowadzania głosowego wykorzystuje mechanizm rozpoznawania mowy. Obowiązuje "<a href="http://m.google.com/privacy">"Polityka prywatności Google Mobile"</a>"."</string> + <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Funkcja wprowadzania głosowego wykorzystuje mechanizm rozpoznawania mowy. Obowiązuje "<a href="http://m.google.com/privacy">"Polityka prywatności w usługach mobilnych"</a>"."</string> <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Aby wyłączyć rozpoznawanie mowy, przejdź do ustawień sposobu wprowadzania tekstu."</string> <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Aby użyć wprowadzania głosowego, naciśnij przycisk mikrofonu."</string> <string name="voice_listening" msgid="467518160751321844">"Mów teraz"</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Włącz przesyłanie opinii użytkownika"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Pomóż ulepszyć edytor wprowadzania tekstu, automatycznie wysyłając do Google statystyki użycia i raporty o awariach."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Motyw klawiatury"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Niemiecka QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Angielska (Wielka Brytania)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Angielska (Stany Zjednoczone)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Tryb badania przydatności"</string> diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml index 0a30235f4..52a497f5f 100644 --- a/java/res/values-pt-rPT/strings.xml +++ b/java/res/values-pt-rPT/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Teclado do Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Teclado Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Definições de teclado do Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opções de introdução"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Correção do Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Definições da verificação ortográfica"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Utilizar dados de prox."</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Util. algoritmo de prox. semelhante a teclado para verif. ortog."</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Procurar nomes de contac."</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"O corretor ortográfico utiliza entradas da sua lista de contactos"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar ao primir as teclas"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Som ao premir as teclas"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Mostrar popup ao premir tecla"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: guardada"</string> <string name="label_go_key" msgid="1635148082137219148">"OK"</string> <string name="label_next_key" msgid="362972844525672568">"Avançar"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Feito"</string> <string name="label_send_key" msgid="2815056534433717444">"Enviar"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Entrada de voz"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Cara sorridente"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Vírgula"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Ponto final"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Parêntese esquerdo"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Parêntese direito"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Dois pontos"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Ponto e vírgula"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Ponto de exclamação"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Ponto de interrogação"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Aspas"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Plica"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Ponto"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Raiz quadrada"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Marca comercial"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Ao cuidado de"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Marcar com estrela"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Cardinal"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Reticências"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Aspas duplas baixas"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Entrada de voz"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Actualmente, a entrada de voz não é suportada para o seu idioma, mas funciona em inglês."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"A entrada de voz utiliza o reconhecimento de voz da Google. É aplicável a "<a href="http://m.google.com/privacy">"Política de privacidade do Google Mobile"</a>"."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Activar comentários do utilizador"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Envie automaticamente estatísticas de utilização e relatórios de falhas para a Google e ajude-nos a melhorar este editor de método de introdução."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Tema do teclado"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"QWERTY Alemão"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Inglês (RU)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Inglês (EUA)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modo de estudo da capacidade de utilização"</string> diff --git a/java/res/values-pt/donottranslate-more-keys.xml b/java/res/values-pt/donottranslate-more-keys.xml index 31d9417ab..868fe7824 100644 --- a/java/res/values-pt/donottranslate-more-keys.xml +++ b/java/res/values-pt/donottranslate-more-keys.xml @@ -19,9 +19,9 @@ --> <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_e">é,ê,è,ę,ė,ē,ë</string> + <string name="more_keys_for_i">í,î,ì,ï,į,ī</string> + <string name="more_keys_for_o">ó,õ,ô,ò,ö,œ,ø,ō,º</string> + <string name="more_keys_for_u">ú,ü,ù,û,ū</string> <string name="more_keys_for_c">ç,č,ć</string> </resources> diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml index 36a70daa6..8d1218910 100644 --- a/java/res/values-pt/strings.xml +++ b/java/res/values-pt/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Teclado Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Teclado Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Configurações de teclado Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opções de entrada"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Correção do Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Configurações de verificação ortográfica"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Usar dados de proximidade"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Usar algoritmo de prox. tipo teclado para verificação ortográfica"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Buscar nomes de contatos"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"O corretor ortográfico usa entradas de sua lista de contatos"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar ao tocar a tecla"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Som ao tocar a tecla"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Exibir pop-up ao digitar"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Salvo"</string> <string name="label_go_key" msgid="1635148082137219148">"Ir"</string> <string name="label_next_key" msgid="362972844525672568">"Avançar"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Feito"</string> <string name="label_send_key" msgid="2815056534433717444">"Enviar"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Entrada de voz"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Carinha sorridente"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Voltar"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Vírgula"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Ponto final"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Parêntese esquerdo"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Parêntese direito"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Dois pontos"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Ponto e vírgula"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Ponto de exclamação"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Ponto de interrogação"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Aspa dupla"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Aspa simples"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Ponto"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Raiz quadrada"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Marca registrada"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Porcentagem"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Asterisco"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Sustenido"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Reticências"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Aspas duplas inferiores"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Entrada de voz"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"A entrada de voz não é suportada no momento para o seu idioma, mas funciona em inglês."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"A entrada de texto por voz usa o reconhecimento de voz do Google. "<a href="http://m.google.com/privacy">"A política de privacidade para celulares"</a>" é aplicada."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Ativar comentário do usuário"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Ajude a melhorar este editor de método de entrada enviando automaticamente ao Google estatísticas de uso e relatórios de falhas."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Tema do teclado"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"QWERTY alemão"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Inglês (Reino Unido)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Inglês (EUA)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modo de estudo de utilização"</string> diff --git a/java/res/values-rm/donottranslate-more-keys.xml b/java/res/values-rm/donottranslate-more-keys.xml index ea9a55944..c40c29b13 100644 --- a/java/res/values-rm/donottranslate-more-keys.xml +++ b/java/res/values-rm/donottranslate-more-keys.xml @@ -18,5 +18,5 @@ */ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="more_keys_for_o">9,ò,ó,ö,ô,õ,œ,ø</string> + <string name="more_keys_for_o">ò,ó,ö,ô,õ,œ,ø</string> </resources> diff --git a/java/res/values-rm/strings.xml b/java/res/values-rm/strings.xml index 090f3fc47..7138da469 100644 --- a/java/res/values-rm/strings.xml +++ b/java/res/values-rm/strings.xml @@ -21,6 +21,8 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Tastatura Android"</string> + <!-- no translation found for aosp_android_keyboard_ime_name (7877134937939182296) --> + <skip /> <string name="english_ime_settings" msgid="6661589557206947774">"Parameters da la tastatura Android"</string> <!-- no translation found for english_ime_input_options (3909945612939668554) --> <skip /> @@ -28,9 +30,9 @@ <skip /> <!-- no translation found for android_spell_checker_settings (5822324635435443689) --> <skip /> - <!-- no translation found for use_proximity_option_title (7469233942295924620) --> + <!-- no translation found for use_contacts_for_spellchecking_option_title (5374120998125353898) --> <skip /> - <!-- no translation found for use_proximity_option_summary (2857708859847261945) --> + <!-- no translation found for use_contacts_for_spellchecking_option_summary (8754413382543307713) --> <skip /> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar cun smatgar in buttun"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Tun cun smatgar in buttun"</string> @@ -76,8 +78,10 @@ <skip /> <!-- no translation found for prefs_settings_key (4623341240804046498) --> <skip /> - <!-- outdated translation 7911639788808958255 --> <string name="auto_correction" msgid="4979925752001319458">"Propostas da pleds"</string> - <!-- outdated translation 6881047311475758267 --> <string name="auto_correction_summary" msgid="5625751551134658006">"Curreger automaticamain il pled precedent"</string> + <!-- no translation found for auto_correction (4979925752001319458) --> + <skip /> + <!-- no translation found for auto_correction_summary (5625751551134658006) --> + <skip /> <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) --> <skip /> <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) --> @@ -86,7 +90,8 @@ <skip /> <!-- no translation found for auto_correction_threshold_mode_very_aggeressive (3386782235540547678) --> <skip /> - <!-- outdated translation 1323347224043514969 --> <string name="bigram_suggestion" msgid="2636414079905220518">"Propostas da tip bigram"</string> + <!-- no translation found for bigram_suggestion (2636414079905220518) --> + <skip /> <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Meglierar la proposta cun agid dal pled precedent"</string> <!-- no translation found for bigram_prediction (8914273444762259739) --> <skip /> @@ -95,6 +100,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Memorisà"</string> <string name="label_go_key" msgid="1635148082137219148">"Dai"</string> <string name="label_next_key" msgid="362972844525672568">"Vinavant"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Finì"</string> <string name="label_send_key" msgid="2815056534433717444">"Trametter"</string> <!-- no translation found for label_to_alpha_key (4793983863798817523) --> @@ -141,51 +148,16 @@ <skip /> <!-- no translation found for spoken_description_return (8178083177238315647) --> <skip /> - <!-- no translation found for spoken_description_comma (4970844442999724586) --> - <skip /> - <!-- no translation found for spoken_description_period (5286614628077903945) --> - <skip /> - <!-- no translation found for spoken_description_left_parenthesis (8524822120595052415) --> - <skip /> - <!-- no translation found for spoken_description_right_parenthesis (1085757995851933164) --> - <skip /> - <!-- no translation found for spoken_description_colon (4312420908484277077) --> - <skip /> - <!-- no translation found for spoken_description_semicolon (37737920987155179) --> - <skip /> - <!-- no translation found for spoken_description_exclamation_mark (2625684427460737157) --> - <skip /> - <!-- no translation found for spoken_description_question_mark (7074097784255379666) --> - <skip /> - <!-- no translation found for spoken_description_double_quote (5485320575389905967) --> - <skip /> - <!-- no translation found for spoken_description_single_quote (4451320362665463938) --> - <skip /> <!-- no translation found for spoken_description_dot (40711082435231673) --> <skip /> - <!-- no translation found for spoken_description_square_root (190595160284757811) --> - <skip /> - <!-- no translation found for spoken_description_pi (4554418247799952239) --> - <skip /> - <!-- no translation found for spoken_description_delta (3607948313655721579) --> - <skip /> - <!-- no translation found for spoken_description_trademark (475877774077871369) --> - <skip /> - <!-- no translation found for spoken_description_care_of (7492800237237796530) --> - <skip /> - <!-- no translation found for spoken_description_star (1009742725387231977) --> - <skip /> - <!-- no translation found for spoken_description_pound (5530577649206922631) --> + <string name="voice_warning_title" msgid="4419354150908395008">"Cumonds vocals"</string> + <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"\"Cumonds vocals en Vossa lingua na vegnan actualmain betg sustegnids, ma la funcziun è disponibla per englais.\""</string> + <!-- no translation found for voice_warning_may_not_understand (5596289095878251072) --> <skip /> - <!-- no translation found for spoken_description_ellipsis (1687670869947652062) --> + <!-- no translation found for voice_warning_how_to_turn_off (3190378129944934856) --> <skip /> - <!-- no translation found for spoken_description_low_double_quote (3551394572784840975) --> + <!-- no translation found for voice_hint_dialog_message (1420686286820661548) --> <skip /> - <string name="voice_warning_title" msgid="4419354150908395008">"Cumonds vocals"</string> - <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"\"Cumonds vocals en Vossa lingua na vegnan actualmain betg sustegnids, ma la funcziun è disponibla per englais.\""</string> - <!-- outdated translation 4611518823070986445 --> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Ils cumonds vocals èn ina funcziunalitad experimentala che utilisescha la renconuschientscha vocala da rait da Google."</string> - <!-- outdated translation 5652369578498701761 --> <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"\"Per deactivar ils cumonds vocals, avri ils parameters da tastatura.\""</string> - <!-- outdated translation 6892342981545727994 --> <string name="voice_hint_dialog_message" msgid="1420686286820661548">"\"Per utilisar ils cumonds vocals, smatgai il buttun dal microfon u stritgai cun il det sur la tastatura dal visur.\""</string> <string name="voice_listening" msgid="467518160751321844">"Ussa discurrer"</string> <string name="voice_working" msgid="6666937792815731889">"Operaziun en progress"</string> <string name="voice_initializing" msgid="661962047129906646"></string> @@ -201,7 +173,8 @@ <string name="voice_punctuation_hint" msgid="1611389463237317754">"\""<b>"Commentari:"</b>" Empruvai la proxima giada d\'agiuntar segns d\'interpuncziun sco \"\"punct\"\", \"\"comma\"\" u \"\"segn da dumonda\"\" cun cumonds vocals.\""</string> <string name="cancel" msgid="6830980399865683324">"Interrumper"</string> <string name="ok" msgid="7898366843681727667">"OK"</string> - <!-- outdated translation 2466640768843347841 --> <string name="voice_input" msgid="3583258583521397548">"Cumonds vocals"</string> + <!-- no translation found for voice_input (3583258583521397548) --> + <skip /> <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) --> <skip /> <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) --> @@ -221,12 +194,12 @@ <string name="language_selection_title" msgid="1651299598555326750">"Linguas da cumonds vocals"</string> <!-- no translation found for select_language (3693815588777926848) --> <skip /> - <!-- outdated translation 8058519710062071085 --> <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← Tippar danovamain per memorisar"</string> + <!-- no translation found for hint_add_to_dictionary (9006292060636342317) --> + <skip /> <string name="has_dictionary" msgid="6071847973466625007">"Dicziunari disponibel"</string> <string name="prefs_enable_log" msgid="6620424505072963557">"Activar il feedback da l\'utilisader"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Gidai a meglierar quest editur da la metoda d\'endataziun cun trametter automaticamain datas statisticas davart l\'utilisaziun e rapports da collaps a Google."</string> - <!-- outdated translation 437433231038683666 --> <string name="keyboard_layout" msgid="8451164783510487501">"Design da la tastatura"</string> - <!-- no translation found for subtype_de_qwerty (3358900499589259491) --> + <!-- no translation found for keyboard_layout (8451164783510487501) --> <skip /> <!-- no translation found for subtype_en_GB (88170601942311355) --> <skip /> diff --git a/java/res/values-ro/donottranslate-more-keys.xml b/java/res/values-ro/donottranslate-more-keys.xml index d7e6a171d..42fd91336 100644 --- a/java/res/values-ro/donottranslate-more-keys.xml +++ b/java/res/values-ro/donottranslate-more-keys.xml @@ -18,8 +18,8 @@ */ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="more_keys_for_a">ă,â,à,á,ä,æ,ã,å,ā</string> - <string name="more_keys_for_i">8,î,ï,ì,í,į,ī</string> + <string name="more_keys_for_a">â,ã,ă,à,á,ä,æ,å,ā</string> + <string name="more_keys_for_i">î,ï,ì,í,į,ī</string> <string name="more_keys_for_s">ș,ß,ś,š</string> - <string name="more_keys_for_t">5,ț</string> + <string name="more_keys_for_t">ț</string> </resources> diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml index c1dea5431..b967eacec 100644 --- a/java/res/values-ro/strings.xml +++ b/java/res/values-ro/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Tastatură Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Tastatură Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Setările tastaturii Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Opţiuni de introducere text"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Corecţie Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Setări de verificare ortografică"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Utiliz. datele de proxim."</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Utilizaţi un algor. de prox. similar tastat. pt. verif. ortograf."</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Verificare nume în agendă"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Verificatorul ortografic utilizează intrări din lista de contacte"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrare la apăsarea tastei"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Sunet la apăsarea tastei"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Fereastră pop-up la apăsarea tastei"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: salvat"</string> <string name="label_go_key" msgid="1635148082137219148">"OK"</string> <string name="label_next_key" msgid="362972844525672568">"Înainte"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Terminat"</string> <string name="label_send_key" msgid="2815056534433717444">"Trimiteţi"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Intrare vocală"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Faţă zâmbitoare"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Virgulă"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Punct"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Paranteză închisă"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Paranteză deschisă"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Două puncte"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Punct şi virgulă"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Semn de exclamaţie"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Semn de întrebare"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Ghilimele duble"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Ghilimele simple"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punct"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Rădăcină pătrată"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Marcă comercială"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"În atenţia"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Stea"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Diez"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Puncte de suspensie"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Ghilimele duble de deschidere"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Intrare voce"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Intrarea vocală nu este acceptată în prezent pentru limba dvs., însă funcţionează în limba engleză."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Intrarea vocală utilizează funcţia Google de recunoaştere vocală. Se aplică "<a href="http://m.google.com/privacy">"Politica de confidenţialitate Google Mobil"</a>"."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Activaţi feedback de la utilizatori"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Ajutaţi la îmbunătăţirea acestui instrument de editare a metodelor de introducere a textului trimiţând în mod automat la Google statistici de utilizare şi rapoarte de blocare."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Temă pentru tastatură"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Tastatură germană QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Engleză (Marea Britanie)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Engleză (S.U.A.)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modul Studiu privind utilizarea"</string> diff --git a/java/res/values-ru/donottranslate-more-keys.xml b/java/res/values-ru/donottranslate-more-keys.xml index f7e006e84..b7e74660d 100644 --- a/java/res/values-ru/donottranslate-more-keys.xml +++ b/java/res/values-ru/donottranslate-more-keys.xml @@ -18,7 +18,5 @@ */ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="more_keys_for_cyrillic_e">5,ё</string> - <string name="more_keys_for_cyrillic_soft_sign">ъ</string> - <string name="more_keys_for_cyrillic_ha">ъ</string> + <string name="more_keys_for_slavic_ye">ё</string> </resources> diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml index 863c8a28c..13607fffa 100644 --- a/java/res/values-ru/strings.xml +++ b/java/res/values-ru/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Клавиатура Android"</string> - <string name="english_ime_settings" msgid="6661589557206947774">"Настройки клавиатуры Android"</string> - <string name="english_ime_input_options" msgid="3909945612939668554">"Параметры ввода"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Клавиатура Android (AOSP)"</string> + <string name="english_ime_settings" msgid="6661589557206947774">"Клавиатура Android"</string> + <string name="english_ime_input_options" msgid="3909945612939668554">"Настройки"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Исправления Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Настройка проверки правописания"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Алгоритм близости клавиш"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Использовать алгоритм близости клавиш для проверки правописания"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Поиск контактов"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Обращаться к списку контактов при проверке правописания"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Виброотклик клавиш"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Звук клавиш"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Увеличение нажатых"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: сохранено"</string> <string name="label_go_key" msgid="1635148082137219148">"Поиск"</string> <string name="label_next_key" msgid="362972844525672568">"Далее"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Готово"</string> <string name="label_send_key" msgid="2815056534433717444">"Отправить"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"АБВ"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Голосовой ввод"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Смайлик"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Клавиша \"Ввод\""</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Запятая"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Точка"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Открывающая скобка"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Закрывающая скобка"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Двоеточие"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Точка с запятой"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Восклицательный знак"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Вопросительный знак"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Двойная кавычка"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Одинарные кавычки"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Точка"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Квадратный корень"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Число \"пи\""</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Дельта"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Товарный знак"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Знак процента"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Пометить"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Английский фунт"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Многоточие"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Нижние двойные кавычки"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Голосовой ввод"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"В настоящее время функция голосового ввода не поддерживает ваш язык, но вы можете пользоваться ей на английском."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Голосовой ввод использует алгоритмы распознавания речи Google. Действует "<a href="http://m.google.com/privacy">"политика конфиденциальности для мобильных устройств"</a>"."</string> @@ -144,9 +128,8 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Включить отправку сведений"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Помогите усовершенствовать редактор способа ввода, разрешив отправку статистики и отчетов о сбоях в Google."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Тема клавиатуры"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Немецкая клавиатура QWERTY"</string> - <string name="subtype_en_GB" msgid="88170601942311355">"Английский (Великобритания)"</string> - <string name="subtype_en_US" msgid="6160452336634534239">"Английский (США)"</string> + <string name="subtype_en_GB" msgid="88170601942311355">"английский (Великобритания)"</string> + <string name="subtype_en_US" msgid="6160452336634534239">"английский (США)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Режим проверки удобства использования"</string> <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Настройки вибросигнала при нажатии клавиш"</string> <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Настройки громкости звука при нажатии клавиш"</string> diff --git a/java/res/values-sk/donottranslate-more-keys.xml b/java/res/values-sk/donottranslate-more-keys.xml index b73db0a46..574eedb1f 100644 --- a/java/res/values-sk/donottranslate-more-keys.xml +++ b/java/res/values-sk/donottranslate-more-keys.xml @@ -18,18 +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_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_a">á,ä,ā,à,â,ã,å,æ,ą</string> + <string name="more_keys_for_e">é,ě,ē,ė,è,ê,ë,ę</string> + <string name="more_keys_for_i">í,ī,į,ì,î,ï,ı</string> + <string name="more_keys_for_o">ô,ó,ö,ò,õ,œ,ő,ø</string> + <string name="more_keys_for_u">ú,ů,ü,ū,ų,ù,û,ű</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_y">ý,ÿ</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_l">ľ,ĺ,ł</string> + <string name="more_keys_for_r">ŕ,ř,ŗ</string> + <string name="more_keys_for_t">ť,ţ</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-sk/strings.xml b/java/res/values-sk/strings.xml index b7ab8f204..c9a5f00b0 100644 --- a/java/res/values-sk/strings.xml +++ b/java/res/values-sk/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Klávesnica Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Klávesnica Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Nastavenia klávesnice Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Možnosti zadávania textu a údajov"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Opravy pravopisu Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Nastavenia kontroly pravopisu"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Použiť údaje o blízkosti"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Na kontr. pravopis. použiť algor. vzdialenosti ako pri kláves."</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Vyhľadať kontakty"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Kontrola pravopisu používa záznamy z vášho zoznamu kontaktov"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Pri stlačení klávesu vibrovať"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Zvuk pri stlačení klávesu"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Zobraziť znaky pri stlačení klávesu"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Uložené"</string> <string name="label_go_key" msgid="1635148082137219148">"Hľadať"</string> <string name="label_next_key" msgid="362972844525672568">"Ďalej"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Hotovo"</string> <string name="label_send_key" msgid="2815056534433717444">"Odoslať"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Hlasový vstup"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Usmiata tvár"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Čiarka"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Bodka"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Ľavá zátvorka"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Pravá zátvorka"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Dvojbodka"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Bodkočiarka"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Výkričník"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Otáznik"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Úvodzovky"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Jednoduché úvodzovky"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Bodka"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Odmocnina"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pí"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Trademark"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Percento"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Hviezdička"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Libra"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Tri bodky"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Dolné úvodzovky"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Hlasový vstup"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Pre váš jazyk aktuálne nie je hlasový vstup podporovaný, ale funguje v angličtine."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Hlasový vstup používa rozpoznávanie hlasu Google. Na používanie hlasového vstupu sa vzťahujú "<a href="http://m.google.com/privacy">"Pravidlá ochrany osobných údajov pre mobilné služby"</a>"."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Povoliť spätnú väzbu od používateľov"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Automatickým zasielaním štatistík o využívaní editora metódy vstupu a správ o jeho zlyhaní do služby Google môžete prispieť k vylepšeniu tohto nástroja."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Motív klávesnice"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Nemecká klávesnica QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Anglická klávesnica (UK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Anglická klávesnica (US)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Režim štúdie použiteľnosti"</string> diff --git a/java/res/values-fr-rCH/donottranslate-more-keys.xml b/java/res/values-sl/donottranslate-more-keys.xml index 561c5e52f..b72c6799e 100644 --- a/java/res/values-fr-rCH/donottranslate-more-keys.xml +++ b/java/res/values-sl/donottranslate-more-keys.xml @@ -18,9 +18,8 @@ */ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="more_keys_for_a">à,â,æ,á,ä,ã,å,ā,ª</string> - <string name="more_keys_for_y">ÿ</string> - <string name="more_keys_for_q">1</string> - <string name="more_keys_for_w">2</string> - <string name="more_keys_for_z">6</string> + <string name="more_keys_for_s">š</string> + <string name="more_keys_for_c">č,ć</string> + <string name="more_keys_for_d">đ</string> + <string name="more_keys_for_z">ž</string> </resources> diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml index d7f357aa0..c1e8a6ff4 100644 --- a/java/res/values-sl/strings.xml +++ b/java/res/values-sl/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Tipkovnica Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Tipkovnica Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Nastavitve tipkovnice Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Možnosti vnosa"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Preverjanje črkovanja za Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Nastavitve preverjanja črkovanja"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Uporabi podatke bližine"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Uporaba algoritma za preverjanje črkovanja na podlagi bližine znakov na tipkovnici"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Iskanje imen stikov"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Črkovalnik uporablja vnose s seznama stikov"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibriranje ob pritisku tipke"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Zvok ob pritisku tipke"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Povečaj črko ob pritisku"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: shranjeno"</string> <string name="label_go_key" msgid="1635148082137219148">"Pojdi"</string> <string name="label_next_key" msgid="362972844525672568">"Naprej"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Dokončano"</string> <string name="label_send_key" msgid="2815056534433717444">"Pošlji"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Glasovni vnos"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Smeško"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Vračalka"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Vejica"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Pika"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Levi oklepaj"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Desni oklepaj"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Dvopičje"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Podpičje"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Klicaj"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Vprašaj"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Dvojni narekovaji"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Enojni narekovaj"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Pika"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Koren"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Blagovna znamka"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Odstotek"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Zvezdica"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Lojtra"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Tri pike"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Spodnji dvojni narekovaji"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Glasovni vnos"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Glasovni vnos trenutno ni podprt v vašem jeziku, deluje pa v angleščini."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Glasovni vnos uporablja Googlovo prepoznavanje govora. Zanj velja "<a href="http://m.google.com/privacy">"pravilnik o zasebnosti za mobilne naprave"</a>"."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Omogoči povratne informacije uporabnikov"</string> <string name="prefs_description_log" msgid="5827825607258246003">"S samodejnim pošiljanjem statističnih podatkov o uporabi in poročil o zrušitvah Googlu nam lahko pomagate izboljšati urejevalnik načina vnosa."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Tema tipkovnice"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Nemška QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"angleščina (Združeno kraljestvo)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"angleščina (ZDA)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Način za preučevanje uporabnosti"</string> diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml index 0906fce6e..20279a852 100644 --- a/java/res/values-sr/strings.xml +++ b/java/res/values-sr/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Android тастатура"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android тастатура (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Подешавања Android тастатуре"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Опције уноса"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Android исправљање"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Подешавања провере правописа"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Употреба података близине"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Употреба алгоритма близине попут тастатуре за проверу правописа"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Потражи имена контаката"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Контролор правописа користи уносе са листе контаката"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Вибрирај на притисак тастера"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Звук на притисак тастера"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Искачући прозор приликом притиска тастера"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Сачувано"</string> <string name="label_go_key" msgid="1635148082137219148">"Иди"</string> <string name="label_next_key" msgid="362972844525672568">"Следеће"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Готово"</string> <string name="label_send_key" msgid="2815056534433717444">"Пошаљи"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Гласовни унос"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Смајли"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Return"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Зарез"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Тачка"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Лева заграда"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Десна заграда"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Две тачке"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Тачка-зарез"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Знак узвика"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Знак питања"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Дупли наводник"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Полунаводник"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Тачка"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Квадратни корен"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Пи"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Делта"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Жиг"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"За"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Звездица"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Фунта"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Три тачке"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Отворени доњи наводници"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Гласовни унос"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Гласовни унос тренутно није подржан за ваш језик, али функционише на енглеском."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Гласовни унос користи Google-ову функцију за препознавање гласа. Примењује се "<a href="http://m.google.com/privacy">"политика приватности за мобилне уређаје"</a>"."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Омогући повратну информацију корисника"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Помозите да се побољша овај уређивач режима уноса тако што ће се аутоматски послати статистика о коришћењу и извештаји о грешкама компанији Google."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Тема тастатуре"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"QWERTY тастатура за немачки"</string> <string name="subtype_en_GB" msgid="88170601942311355">"енглески (УК)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"енглески (САД)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Режим за студију могућности коришћења"</string> diff --git a/java/res/values-sv/donottranslate-more-keys.xml b/java/res/values-sv/donottranslate-more-keys.xml index 1fa29a83e..6d9800e57 100644 --- a/java/res/values-sv/donottranslate-more-keys.xml +++ b/java/res/values-sv/donottranslate-more-keys.xml @@ -18,10 +18,11 @@ */ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="more_keys_for_e">3,é,è,ê,ë,ę</string> - <string name="more_keys_for_o">9,œ,ô,ò,ó,õ,ō</string> - <string name="more_keys_for_u">7,ü,û,ù,ú,ū</string> + <string name="more_keys_for_e">é,è,ê,ë,ę</string> + <string name="more_keys_for_o">œ,ô,ò,ó,õ,ō</string> + <string name="more_keys_for_u">ü,û,ù,ú,ū</string> <string name="more_keys_for_s">ß,ś,š</string> + <string name="keylabel_for_scandinavia_row1_11">å</string> <string name="keylabel_for_scandinavia_row2_10">ö</string> <string name="keylabel_for_scandinavia_row2_11">ä</string> <string name="more_keys_for_scandinavia_row2_10">ø</string> diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml index 46760bbe2..eb2007382 100644 --- a/java/res/values-sv/strings.xml +++ b/java/res/values-sv/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Androids tangentbord"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Androids tangentbord (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Inställningar för Androids tangentbord"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Inmatningsalternativ"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Android-korrigering"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Inställningar för stavningskontroll"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Använd närhetsinformation"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Använd tangentbordsliknande närhetsalgoritm för stavningskontroll"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Sök namn på kontakter"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"I stavningskontrollen används poster från kontaktlistan"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrera vid tangenttryck"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Knappljud"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Popup vid knapptryck"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: sparat"</string> <string name="label_go_key" msgid="1635148082137219148">"Kör"</string> <string name="label_next_key" msgid="362972844525672568">"Nästa"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Färdig"</string> <string name="label_send_key" msgid="2815056534433717444">"Skicka"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Röstinmatning"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Uttryckssymbol"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Retur"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Komma"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Punkt"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Vänster parentes"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Högerparentes"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Kolon"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Semikolon"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Utropstecken"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Frågetecken"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Dubbla citattecken"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Enkla citattecken"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Punkt"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Kvadratrot"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Trademark"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Care of"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Stjärna"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Fyrkant"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Ellips"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Nedre dubbla citattecken"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Röstindata"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Röstindata stöds inte på ditt språk än, men tjänsten fungerar på engelska."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Röstinmatning använder sig av Googles tjänst för taligenkänning. "<a href="http://m.google.com/privacy">"Sekretesspolicyn för mobila enheter"</a>" gäller."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Aktivera synpunkter från användare"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Du kan hjälpa till att förbättra inmatningsmetoden genom att automatiskt skicka användningsstatistik och felrapporter till Google."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Tangentbordstema"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Tyskt QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Engelskt (brittiskt)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Engelskt (amerikanskt)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Läge för studie av användbarhet"</string> diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml index 822907b05..983754014 100644 --- a/java/res/values-sw/strings.xml +++ b/java/res/values-sw/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Kibodi ya Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Kicharazio cha Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Mipangilio ya kibodi ya Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Chaguo za uingizaji"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Masahihisho ya Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Mipangilio ya kukagua sarufi"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Tumia data ya ukaribu"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Tumia kibodi kama ukaribu wa algorithmu kwa ukaguzi wa sarufi"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Angalia majina ya wasiliani"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Kikagua tahajia hutumia ingizo kutoka kwa orodha yako ya anwani"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Tetema unabofya kitufe"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Toa sauti unapobofya kitufe"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Ibuka kitufe kinapobonyezwa"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Imehifadhiwa"</string> <string name="label_go_key" msgid="1635148082137219148">"Nenda"</string> <string name="label_next_key" msgid="362972844525672568">"Ifuatayo"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Kwisha"</string> <string name="label_send_key" msgid="2815056534433717444">"Tuma"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Uingizaji sauti"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Uso wenye tabasamu"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Rudi"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Koma"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Muda"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Mabano ya kushoto"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"mabano ya kulia"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Nukta mbili juu na chini"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Semikoloni"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Alama ya mshangao"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Alama ya kiulizio"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Nukuu mara mbili"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Nukuu moja"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Nukta"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Square root"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Chapa ya Biashara"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Kwa ulinzi wa"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Nyota"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Pauni"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Ellipsis"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Nukuu ya chini maradufu"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Uingizaji wa sauti"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Uingizaji wa sauti hauhimiliwi kwa lugha yako kwa sasa, lakini inafanya kazi kwa Kiingereza."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Uingizaji wa sauti hutumia utambuaji wa usemi wa Google. "<a href="http://m.google.com/privacy">"Sera ya Faragha ya Simu za mkononi "</a>" hutumika."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Wezesha maoni ya watumiaji"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Saidia kuimarisha mbinu ya uingizaji wa kihariri, kwa kutuma takwimu za matumizi na ripoti za kuvurugika kwa Google kiotomatiki."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Maandhari ya kibodi"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"QWERTY ya Kijerumani"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Kiingereza cha (Uingereza)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Kiingereza cha (Marekani)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modi ya uchunguzi wa utumizi"</string> diff --git a/java/res/values-sw600dp-land/dimens.xml b/java/res/values-sw600dp-land/dimens.xml index 1b8c8a64a..1c725a484 100644 --- a/java/res/values-sw600dp-land/dimens.xml +++ b/java/res/values-sw600dp-land/dimens.xml @@ -48,6 +48,7 @@ <fraction name="key_hint_letter_ratio">23%</fraction> <fraction name="key_hint_label_ratio">34%</fraction> <fraction name="key_uppercase_letter_ratio">29%</fraction> + <fraction name="spacebar_text_ratio">33.33%</fraction> <dimen name="suggestions_strip_padding">40.0mm</dimen> <integer name="max_more_suggestions_row">5</integer> diff --git a/java/res/values-sw600dp/config.xml b/java/res/values-sw600dp/config.xml index 1854a8696..ecc5b7136 100644 --- a/java/res/values-sw600dp/config.xml +++ b/java/res/values-sw600dp/config.xml @@ -24,20 +24,22 @@ <bool name="config_enable_show_voice_key_option">false</bool> <bool name="config_enable_show_popup_on_keypress_option">false</bool> <bool name="config_enable_bigram_suggestions_option">false</bool> - <bool name="config_sliding_key_input_enabled">false</bool> - <bool name="config_digit_more_keys_enabled">false</bool> <!-- Whether or not Popup on key press is enabled by default --> <bool name="config_default_popup_preview">false</bool> <bool name="config_default_sound_enabled">true</bool> <bool name="config_auto_correction_spacebar_led_enabled">false</bool> - <!-- Showing mini keyboard, just above the touched point if true, aligned to the key if false --> - <bool name="config_show_mini_keyboard_at_touched_point">true</bool> <!-- The language is never displayed if == 0, always displayed if < 0 --> <integer name="config_delay_before_fadeout_language_on_spacebar">1200</integer> <!-- Long pressing space will invoke IME switcher if > 0, never invoke IME switcher if == 0 --> <integer name="config_long_press_space_key_timeout">0</integer> <!-- This configuration is the index of the array {@link KeyboardSwitcher.KEYBOARD_THEMES}. --> <string name="config_default_keyboard_theme_id" translatable="false">5</string> - <string name="config_text_size_of_language_on_spacebar" translatable="false">medium</string> <integer name="config_max_more_keys_column">5</integer> + <!-- + Configuration for LatinKeyboardView + --> + <bool name="config_sliding_key_input_enabled">false</bool> + <!-- Showing more keys keyboard, just above the touched point if true, aligned to the key if + false --> + <bool name="config_show_more_keys_keyboard_at_touched_point">true</bool> </resources> diff --git a/java/res/values-sw600dp/dimens.xml b/java/res/values-sw600dp/dimens.xml index 31830239d..e04609f2a 100644 --- a/java/res/values-sw600dp/dimens.xml +++ b/java/res/values-sw600dp/dimens.xml @@ -40,12 +40,12 @@ <fraction name="keyboard_bottom_padding_ics">0.0%p</fraction> - <dimen name="mini_keyboard_key_horizontal_padding">6dip</dimen> + <dimen name="more_keys_keyboard_key_horizontal_padding">6dip</dimen> <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. --> <!-- popup_key_height x 1.2 --> - <dimen name="mini_keyboard_slide_allowance">15.6mm</dimen> + <dimen name="more_keys_keyboard_slide_allowance">15.6mm</dimen> <!-- popup_key_height x -1.0 --> - <dimen name="mini_keyboard_vertical_correction">-13.0mm</dimen> + <dimen name="more_keys_keyboard_vertical_correction">-13.0mm</dimen> <!-- left or right padding of label alignment --> <dimen name="key_label_horizontal_padding">6dip</dimen> @@ -59,6 +59,7 @@ <fraction name="key_hint_label_ratio">28%</fraction> <fraction name="key_uppercase_letter_ratio">26%</fraction> <fraction name="key_preview_text_ratio">50%</fraction> + <fraction name="spacebar_text_ratio">32.14%</fraction> <dimen name="key_preview_height">15.0mm</dimen> <dimen name="key_preview_offset">0.1in</dimen> diff --git a/java/res/values-sw768dp-land/dimens.xml b/java/res/values-sw768dp-land/dimens.xml index 664e8c159..ef39f4393 100644 --- a/java/res/values-sw768dp-land/dimens.xml +++ b/java/res/values-sw768dp-land/dimens.xml @@ -52,6 +52,7 @@ <fraction name="key_hint_letter_ratio">23%</fraction> <fraction name="key_hint_label_ratio">28%</fraction> <fraction name="key_uppercase_letter_ratio">24%</fraction> + <fraction name="spacebar_text_ratio">24.00%</fraction> <dimen name="key_preview_height">17.0mm</dimen> <dimen name="key_preview_height_ics">26.5mm</dimen> diff --git a/java/res/values-sw768dp/config.xml b/java/res/values-sw768dp/config.xml index c25139a42..c1f9179ee 100644 --- a/java/res/values-sw768dp/config.xml +++ b/java/res/values-sw768dp/config.xml @@ -24,20 +24,22 @@ <bool name="config_enable_show_voice_key_option">false</bool> <bool name="config_enable_show_popup_on_keypress_option">false</bool> <bool name="config_enable_bigram_suggestions_option">false</bool> - <bool name="config_sliding_key_input_enabled">false</bool> - <bool name="config_digit_more_keys_enabled">false</bool> <!-- Whether or not Popup on key press is enabled by default --> <bool name="config_default_popup_preview">false</bool> <bool name="config_default_sound_enabled">true</bool> <bool name="config_auto_correction_spacebar_led_enabled">false</bool> - <!-- Showing mini keyboard, just above the touched point if true, aligned to the key if false --> - <bool name="config_show_mini_keyboard_at_touched_point">true</bool> <!-- Long pressing space will invoke IME switcher if > 0, never invoke IME switcher if == 0 --> <integer name="config_long_press_space_key_timeout">0</integer> <!-- This configuration is the index of the array {@link KeyboardSwitcher.KEYBOARD_THEMES}. --> <string name="config_default_keyboard_theme_id" translatable="false">5</string> - <string name="config_text_size_of_language_on_spacebar" translatable="false">medium</string> <integer name="config_max_more_keys_column">5</integer> + <!-- + Configuration for LatinKeyboardView + --> + <bool name="config_sliding_key_input_enabled">false</bool> + <!-- Showing more keys keyboard, just above the touched point if true, aligned to the key if + false --> + <bool name="config_show_more_keys_keyboard_at_touched_point">true</bool> <!-- Screen metrics for logging. 0 = "mdpi phone screen" 1 = "hdpi phone screen" diff --git a/java/res/values-sw768dp/dimens.xml b/java/res/values-sw768dp/dimens.xml index bb4937dd5..f33a657af 100644 --- a/java/res/values-sw768dp/dimens.xml +++ b/java/res/values-sw768dp/dimens.xml @@ -43,12 +43,12 @@ <dimen name="popup_key_height">10.0mm</dimen> - <dimen name="mini_keyboard_key_horizontal_padding">12dip</dimen> + <dimen name="more_keys_keyboard_key_horizontal_padding">12dip</dimen> <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. --> <!-- popup_key_height x 1.2 --> - <dimen name="mini_keyboard_slide_allowance">15.6mm</dimen> + <dimen name="more_keys_keyboard_slide_allowance">15.6mm</dimen> <!-- popup_key_height x -1.0 --> - <dimen name="mini_keyboard_vertical_correction">-13.0mm</dimen> + <dimen name="more_keys_keyboard_vertical_correction">-13.0mm</dimen> <!-- left or right padding of label alignment --> <dimen name="key_label_horizontal_padding">6dip</dimen> @@ -62,6 +62,7 @@ <fraction name="key_hint_label_ratio">28%</fraction> <fraction name="key_uppercase_letter_ratio">26%</fraction> <fraction name="key_preview_text_ratio">50%</fraction> + <fraction name="spacebar_text_ratio">29.03%</fraction> <dimen name="key_preview_height">15.0mm</dimen> <dimen name="key_preview_offset">0.1in</dimen> diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml index 53f56606c..700361a7b 100644 --- a/java/res/values-th/strings.xml +++ b/java/res/values-th/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"แป้นพิมพ์ Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android keyboard (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"การตั้งค่าแป้นพิมพ์ Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"ตัวเลือกการป้อนข้อมูล"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"การแก้ไขของ Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"การตั้งค่าการตรวจสอบการสะกด"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"ใช้ข้อมูลที่ใกล้เคียง"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"ใช้อัลกอริทึมใกล้เคียงที่คล้ายกับแป้นพิมพ์สำหรับตรวจสอบการสะกด"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"ค้นหารายชื่อติดต่อ"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"เครื่องมือตรวจการสะกดใช้รายการจากรายชื่อติดต่อของคุณ"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"สั่นเมื่อกดปุ่ม"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"ส่งเสียงเมื่อกดปุ่ม"</string> <string name="popup_on_keypress" msgid="123894815723512944">"ป๊อปอัปเมื่อกดแป้น"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : บันทึกแล้ว"</string> <string name="label_go_key" msgid="1635148082137219148">"ไป"</string> <string name="label_next_key" msgid="362972844525672568">"ถัดไป"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"เสร็จสิ้น"</string> <string name="label_send_key" msgid="2815056534433717444">"ส่ง"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"การป้อนข้อมูลด้วยเสียง"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"หน้ายิ้ม"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Return"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"เครื่องหมายจุลภาค"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"มหัพภาค"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"วงเล็บซ้าย"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"วงเล็บขวา"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"เครื่องหมายจุดคู่"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"อัฒภาค"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"อัศเจรีย์"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"เครื่องหมายคำถาม"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"อัญประกาศ"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"เครื่องหมายคำพูดเดี่ยว"</string> <string name="spoken_description_dot" msgid="40711082435231673">"เครื่องหมายจุด"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"รากที่สอง"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"เดลตา"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"เครื่องหมายการค้า"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Care of"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"ติดดาว"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"ปอนด์"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"จุดไข่ปลา"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"อัญประกาศล่าง"</string> <string name="voice_warning_title" msgid="4419354150908395008">"การป้อนข้อมูลด้วยเสียง"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"ขณะนี้การป้อนข้อมูลด้วยเสียงยังไม่ได้รับการสนับสนุนในภาษาของคุณ แต่ใช้ได้ในภาษาอังกฤษ"</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"ป้อนข้อมูลด้วยเสียงใช้การจดจำคำพูดของ Google "<a href="http://m.google.com/privacy">" นโยบายส่วนบุคคลของมือถือ"</a>"มีผลบังคับใช้"</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"เปิดใช้งานการแสดงความคิดเห็นจากผู้ใช้"</string> <string name="prefs_description_log" msgid="5827825607258246003">"ช่วยปรับปรุงตัวแก้ไขวิธีการป้อนข้อมูลนี้โดยการส่งสถิติการใช้งานและรายงานการขัดข้องถึง Google โดยอัตโนมัติ"</string> <string name="keyboard_layout" msgid="8451164783510487501">"ชุดรูปแบบแป้นพิมพ์"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"QWERTY ภาษาเยอรมัน"</string> <string name="subtype_en_GB" msgid="88170601942311355">"อังกฤษ (สหราชอาณาจักร)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"อังกฤษ (อเมริกัน)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"โหมดศึกษาประโยชน์ในการใช้งาน"</string> diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml index 701963f2a..812d200ef 100644 --- a/java/res/values-tl/strings.xml +++ b/java/res/values-tl/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Android keyboard"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android keyboard (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Mga setting ng Android keyboard"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Mga pagpipilian sa input"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Pagwawasto sa Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Mga setting ng pang-check ng pagbabaybay"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Gamitin ang proximity data"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Gumamit ng proximity algorithm na tulad ng keyboard para sa pag-check ng pagbabaybay"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Maghanap pangalan contact"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Gumagamit pang-check pagbabaybay entry sa iyong listahan contact"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Mag-vibrate sa keypress"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Tunog sa keypress"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Popup sa keypress"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Na-save"</string> <string name="label_go_key" msgid="1635148082137219148">"Punta"</string> <string name="label_next_key" msgid="362972844525672568">"Susunod"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Tapos na"</string> <string name="label_send_key" msgid="2815056534433717444">"Ipadala"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Input ng boses"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Smiley na mukha"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Bumalik"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Kuwit"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Tuldok"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Kaliwang panaklong"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Kanang panaklong"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Tutuldok"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Tuldukuwit"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Tandang padamdam"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Tandang pananong"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Panipi"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Kudlit"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Tuldok"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Square root"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Trademark"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Care of"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Star"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Pound"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Ellipsis"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Mababang panipi"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Pag-input ng boses"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Hindi kasalukuyang suportado ang pag-input ng boses para sa iyong wika, ngunit gumagana sa Ingles."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Gumagamit ang pag-input ng boses ng speech recognition ng Google. Nalalapat "<a href="http://m.google.com/privacy">"Ang Patakaran sa Privacy ng Mobile"</a>"."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Paganahin ang feedback ng user"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Tumulong na pahusayin ang editor ng paraan ng pag-input na ito sa pamamagitan ng awtomatikong pagpapadala ng mga istatistika ng paggamit at mga ulat ng crash sa Google."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Tema ng keyboard"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"German na QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Ingles (UK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Ingles (Estados Unidos)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Study mode ng pagiging kapaki-pakinabang"</string> diff --git a/java/res/values-tr/donottranslate-more-keys.xml b/java/res/values-tr/donottranslate-more-keys.xml index 6906b3580..227ebf98c 100644 --- a/java/res/values-tr/donottranslate-more-keys.xml +++ b/java/res/values-tr/donottranslate-more-keys.xml @@ -19,9 +19,9 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="more_keys_for_a">â</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_i">ı,î,ï,ì,í,į,ī</string> + <string name="more_keys_for_o">ö,ô,œ,ò,ó,õ,ø,ō</string> + <string name="more_keys_for_u">ü,û,ù,ú,ū</string> <string name="more_keys_for_s">ş,ß,ś,š</string> <string name="more_keys_for_g">ğ</string> <string name="more_keys_for_c">ç,ć,č</string> diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml index 4ae7d78c9..d67def9e3 100644 --- a/java/res/values-tr/strings.xml +++ b/java/res/values-tr/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Android klavyesi"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android klavye (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Android klavye ayarları"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Giriş seçenekleri"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Android düzeltme"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Yazım denetimi ayarları"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Yakınlık verilri kullan"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Yazım denetimi içn klavye benzeri yakınlık algoritması kullan"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Kişi adlarını denetle"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Yazım denetleyici, kişi listenizdeki girişleri kullanır"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Tuşa basıldığında titret"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Tuşa basıldığında ses çıkar"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Tuşa basıldığında pop-up aç"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Kaydedildi"</string> <string name="label_go_key" msgid="1635148082137219148">"Git"</string> <string name="label_next_key" msgid="362972844525672568">"İleri"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Bitti"</string> <string name="label_send_key" msgid="2815056534433717444">"Gönder"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Ses girişi"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Gülen yüz"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Enter"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Virgül"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Nokta"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Sol parantez"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Sağ parantez"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"İki Nokta"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Noktalı virgül"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Ünlem işareti"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Soru işareti"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Çift tırnak"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Tek tırnak işareti"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Nokta"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Karekök"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Ticari marka"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Yüzde işareti"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Yıldız"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Kare"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Üç nokta"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Alt çift tırnak"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Ses girişi"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Ses girişi, şu anda sizin diliniz için desteklenmiyor ama İngilizce dilinde kullanılabilir."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Ses girişi Google\'ın konuşma tanıma işlevini kullanır. "<a href="http://m.google.com/privacy">" Mobil Gizlilik Politikası"</a>" geçerlidir."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Kullanıcı geri bildirimini etkinleştir"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Kullanım istatistiklerini ve kilitlenme raporlarını Google\'a otomatik olarak göndererek bu giriş yöntemi düzenleyicisinin iyileştirilmesine yardımcı olun."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Klavye teması"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Almanca QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"İngilizce (BK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"İngilizce (ABD)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Kullanılabilirlik çalışması modu"</string> diff --git a/java/res/values-uk/donottranslate-more-keys.xml b/java/res/values-uk/donottranslate-more-keys.xml new file mode 100644 index 000000000..4e7910128 --- /dev/null +++ b/java/res/values-uk/donottranslate-more-keys.xml @@ -0,0 +1,23 @@ +<?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="keylabel_for_slavic_yery">і</string> + <string name="more_keys_for_slavic_yery">ї</string> +</resources> diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml index 234a9c56a..71ae6d152 100644 --- a/java/res/values-uk/strings.xml +++ b/java/res/values-uk/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Клавіатура Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Клавіатура Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Налашт-ня клавіат. Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Парам. введення"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Виправлення Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Налаштування перевірки орфографії"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Використ. дані близькості"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Для перевірки орфогр. викор. алгоритм близьк., аналог. клавіат."</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Шукати імена контактів"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Програма перевірки правопису використ. записи зі списку контактів"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Вібр при натиску клав."</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Звук при натиску клав."</string> <string name="popup_on_keypress" msgid="123894815723512944">"Сплив. при нат.клав."</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : збережено"</string> <string name="label_go_key" msgid="1635148082137219148">"Іти"</string> <string name="label_next_key" msgid="362972844525672568">"Далі"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Готово"</string> <string name="label_send_key" msgid="2815056534433717444">"Надісл."</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"Алфавіт"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Голосовий ввід"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Смайлик"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Клавіша Return"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Кома"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Крапка"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Ліва дужка"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Права дужка"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Двокрапка"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Крапка з комою"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Знак оклику"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Знак питання"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Подвійні лапки"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Одинарні лапки"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Крапка"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Квадратний корінь"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Пі"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Дельта"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Торговельна марка"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Через"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Зірочка"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Решітка"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Три крапки"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Нижні подвійні лапки"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Голос. ввід"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Голос. ввід наразі не підтрим. для вашої мови, але можна користуватися англійською."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Голосовий ввід використовує розпізнавання мовлення Google. Застосовується "<a href="http://m.google.com/privacy">"Політика конфіденційності для мобільних пристроїв"</a>"."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Увімк. відгуки корист."</string> <string name="prefs_description_log" msgid="5827825607258246003">"Допоможіть покращ. редактор методу введ., автомат. надсилаючи в Google статистику використ. та звіти про збої."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Тема клавіатури"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Німецька клавіатура QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Англійська (Великобританія)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Англійська (США)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Режим вивчення зручності у використанні"</string> diff --git a/java/res/values-vi/donottranslate-more-keys.xml b/java/res/values-vi/donottranslate-more-keys.xml new file mode 100644 index 000000000..9e2f6b8fd --- /dev/null +++ b/java/res/values-vi/donottranslate-more-keys.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. +*/ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="more_keys_for_a">à,á,ả,ã,ạ,ă,ằ,ắ,ẳ,ẵ,ặ,â,ầ,ấ,ẩ,ẫ,ậ</string> + <string name="more_keys_for_e">è,é,ẻ,ẽ,ẹ,ê,ề,ế,ể,ễ,ệ</string> + <string name="more_keys_for_i">ì,í,ỉ,ĩ,ị</string> + <string name="more_keys_for_o">ò,ó,ỏ,õ,ọ,ô,ồ,ố,ổ,ỗ,ộ,ơ,ờ,ớ,ở,ỡ,ợ</string> + <string name="more_keys_for_u">ù,ú,ủ,ũ,ụ,ư,ừ,ứ,ử,ữ,ự</string> + <string name="more_keys_for_y">ỳ,ý,ỷ,ỹ,ỵ</string> + <string name="more_keys_for_d">đ</string> +</resources> diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml index e602b495a..7d6a85400 100644 --- a/java/res/values-vi/strings.xml +++ b/java/res/values-vi/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Bàn phím Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Bàn phím Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Cài đặt bàn phím Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Tùy chọn nhập"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Dịch vụ sửa chính tả của Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Cài đặt kiểm tra chính tả"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Sử dụng dữ liệu gần"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Dùng thuật toán gần, như của bàn phím để k.tra chính tả"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Tra cứu tên liên hệ"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Trình kiểm tra chính tả sử dụng các mục nhập từ danh sách liên hệ của bạn"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Rung khi nhấn phím"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Âm thanh khi nhấn phím"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Cửa sổ bật lên khi nhấn phím"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Đã lưu"</string> <string name="label_go_key" msgid="1635148082137219148">"Tìm"</string> <string name="label_next_key" msgid="362972844525672568">"Tiếp theo"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Xong"</string> <string name="label_send_key" msgid="2815056534433717444">"Gửi"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Nhập dữ liệu bằng giọng nói"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Mặt cười"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Quay lại"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Dấu phẩy"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Dấu chấm"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"Dấu ngoặc trái"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"Dấu ngoặc phải"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Dấu hai chấm"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Dấu chấm phẩy"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Dấu hỏi chấm"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Dấu chấm hỏi"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Dấu ngoặc kép"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Dấu nháy đơn"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Dấu chấm"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Dấu khai căn"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Số Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Thương hiệu"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Dấu phần trăm"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Dấu sao"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Dấu thăng"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Dấu ba chấm"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Dấu nháy kép dưới"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Nhập liệu bằng giọng nói"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Nhập liệu bằng giọng nói hiện không được hỗ trợ cho ngôn ngữ của bạn nhưng hoạt động với ngôn ngữ tiếng Anh."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Nhập liệu bằng giọng nói sử dụng nhận dạng giọng nói của Google. Áp dụng "<a href="http://m.google.com/privacy">"Chính sách bảo mật dành cho điện thoại di động"</a>"."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Bật phản hồi của người dùng"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Giúp nâng cao trình chỉnh sửa phương thức nhập này bằng cách tự động gửi thống kê sử dụng và báo cáo sự cố cho Google."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Chủ đề bàn phím"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"Bàn phím QWERTY tiếng Đức"</string> <string name="subtype_en_GB" msgid="88170601942311355">"Tiếng Anh (Anh)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"Tiếng Anh (Mỹ)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Chế độ nghiên cứu tính khả dụng"</string> diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml index c3adf23c0..65729265f 100644 --- a/java/res/values-zh-rCN/strings.xml +++ b/java/res/values-zh-rCN/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Android 键盘"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android 键盘 (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Android 键盘设置"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"输入选项"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Android 更正"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"拼写检查设置"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"使用邻近度数据"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"使用类似键盘的邻近度算法进行拼写检查"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"查找联系人姓名"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"拼写检查工具会使用您的联系人列表中的条目"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"按键时振动"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"按键时播放音效"</string> <string name="popup_on_keypress" msgid="123894815723512944">"按键时显示弹出窗口"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:已保存"</string> <string name="label_go_key" msgid="1635148082137219148">"开始"</string> <string name="label_next_key" msgid="362972844525672568">"下一步"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"完成"</string> <string name="label_send_key" msgid="2815056534433717444">"发送"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"语音输入"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"笑脸"</string> <string name="spoken_description_return" msgid="8178083177238315647">"返回"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"逗号"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"句号"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"左括号"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"右括号"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"冒号"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"分号"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"感叹号"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"问号"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"双引号"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"单引号"</string> <string name="spoken_description_dot" msgid="40711082435231673">"点"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"平方根"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"圆周率"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"商标符号"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"百分号"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"星号"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"井号"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"省略号"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"低双引号"</string> <string name="voice_warning_title" msgid="4419354150908395008">"语音输入"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"语音输入功能当前还不支持您的语言,您只能输入英语语音。"</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"语音输入采用了 Google 的语音识别技术,因此请遵守"<a href="http://m.google.com/privacy">"“Google 移动”隐私权政策"</a>"。"</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"启用用户反馈"</string> <string name="prefs_description_log" msgid="5827825607258246003">"自动向 Google 发送使用情况统计信息和崩溃报告,帮助改进该输入法编辑器。"</string> <string name="keyboard_layout" msgid="8451164783510487501">"键盘主题"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"德语 QWERTY 键盘"</string> <string name="subtype_en_GB" msgid="88170601942311355">"英语(英国)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"英语(美国)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"可用性研究模式"</string> diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml index 8d60fb7cd..5ac3a38c8 100644 --- a/java/res/values-zh-rTW/strings.xml +++ b/java/res/values-zh-rTW/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Android 鍵盤"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android 鍵盤 (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Android 鍵盤設定"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"輸入選項"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Android 拼字修正服務"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"拼字檢查設定"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"使用鄰近資料"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"運用類似鍵盤的鄰近演算法進行拼字檢查"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"查詢聯絡人姓名"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"拼字檢查程式使用您的聯絡人清單項目"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"按鍵時震動"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"按鍵時播放音效"</string> <string name="popup_on_keypress" msgid="123894815723512944">"按鍵時顯示彈出式視窗"</string> @@ -50,7 +51,7 @@ <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"一律顯示"</string> <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"以垂直模式顯示"</string> <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"永遠隱藏"</string> - <string name="prefs_settings_key" msgid="4623341240804046498">"顯示設定金鑰"</string> + <string name="prefs_settings_key" msgid="4623341240804046498">"顯示設定鍵"</string> <string name="auto_correction" msgid="4979925752001319458">"自動修正"</string> <string name="auto_correction_summary" msgid="5625751551134658006">"按空白鍵或標點符號時,自動修正前面的錯字"</string> <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"關閉"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:已儲存"</string> <string name="label_go_key" msgid="1635148082137219148">"開始"</string> <string name="label_next_key" msgid="362972844525672568">"繼續"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"完成"</string> <string name="label_send_key" msgid="2815056534433717444">"傳送"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"語音輸入"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"笑臉"</string> <string name="spoken_description_return" msgid="8178083177238315647">"返回"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"逗號"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"句號"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"左括弧"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"右括弧"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"冒號"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"分號"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"驚嘆號"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"問號"</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"雙引號"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"單引號"</string> <string name="spoken_description_dot" msgid="40711082435231673">"點"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"平方根"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"圓周率"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"商標"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"百分比"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"星號"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"井字鍵"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"省略符號"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"下雙引號"</string> <string name="voice_warning_title" msgid="4419354150908395008">"語音輸入"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"語音輸入目前不支援您的語言,但是可以辨識英文。"</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"語音輸入使用 Google 的語音辨識功能,並遵循《"<a href="http://m.google.com/privacy">"行動服務隱私權政策"</a>"》。"</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"啟用使用者意見回饋"</string> <string name="prefs_description_log" msgid="5827825607258246003">"自動將使用統計資料和當機報告傳送給 Google,協助改善這個輸入法編輯器。"</string> <string name="keyboard_layout" msgid="8451164783510487501">"鍵盤主題"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"德文 QWERTY"</string> <string name="subtype_en_GB" msgid="88170601942311355">"英文 (英式)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"英文 (美式)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"使用性研究模式"</string> diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml index 072d17cba..012bf7fc9 100644 --- a/java/res/values-zu/strings.xml +++ b/java/res/values-zu/strings.xml @@ -21,12 +21,13 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="english_ime_name" msgid="7252517407088836577">"Ikhibhodi ye-Android"</string> + <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Ikhibhodi ye-Android (AOSP)"</string> <string name="english_ime_settings" msgid="6661589557206947774">"Izilungiselelo zekhibhodi ye-Android"</string> <string name="english_ime_input_options" msgid="3909945612939668554">"Okukhethwa kukho kokungenayo"</string> <string name="spell_checker_service_name" msgid="2003013122022285508">"Ukulungisa kwe-Android"</string> <string name="android_spell_checker_settings" msgid="5822324635435443689">"Izilungiselelo zokuhlola ukupela"</string> - <string name="use_proximity_option_title" msgid="7469233942295924620">"Sebenzisa imininingo ye-proximity"</string> - <string name="use_proximity_option_summary" msgid="2857708859847261945">"Sebenzisa i-proximity algorithm efana ne-keyboard ukuhlola ukupela"</string> + <string name="use_contacts_for_spellchecking_option_title" msgid="5374120998125353898">"Bheka amagama woxhumana nabo"</string> + <string name="use_contacts_for_spellchecking_option_summary" msgid="8754413382543307713">"Isihloli sokupela sisebenzisa okungenayo kusuka kuhlu lalabo oxhumana nabo"</string> <string name="vibrate_on_keypress" msgid="5258079494276955460">"Dlidlizelisa ngokucindezela inkinobho"</string> <string name="sound_on_keypress" msgid="6093592297198243644">"Umsindo wokucindezela ukhiye"</string> <string name="popup_on_keypress" msgid="123894815723512944">"Ugaxekile ngokucindezela ukhiye"</string> @@ -64,6 +65,8 @@ <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Kulondoloziwe"</string> <string name="label_go_key" msgid="1635148082137219148">"Iya"</string> <string name="label_next_key" msgid="362972844525672568">"Okulandelayo"</string> + <!-- no translation found for label_previous_key (1211868118071386787) --> + <skip /> <string name="label_done_key" msgid="2441578748772529288">"Kwenziwe"</string> <string name="label_send_key" msgid="2815056534433717444">"Thumela"</string> <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string> @@ -88,26 +91,7 @@ <string name="spoken_description_mic" msgid="615536748882611950">"Okungenayo kwezwi"</string> <string name="spoken_description_smiley" msgid="2256309826200113918">"Ubuso-obumomothekayo"</string> <string name="spoken_description_return" msgid="8178083177238315647">"Buyisela"</string> - <string name="spoken_description_comma" msgid="4970844442999724586">"Ikhefu"</string> - <string name="spoken_description_period" msgid="5286614628077903945">"Isikhathi"</string> - <string name="spoken_description_left_parenthesis" msgid="8524822120595052415">"ama-parenthesis esobunxele"</string> - <string name="spoken_description_right_parenthesis" msgid="1085757995851933164">"I-parenthesis yesokudla"</string> - <string name="spoken_description_colon" msgid="4312420908484277077">"Ikholoni"</string> - <string name="spoken_description_semicolon" msgid="37737920987155179">"Ikhefanangqi"</string> - <string name="spoken_description_exclamation_mark" msgid="2625684427460737157">"Uphawu lokumemeza"</string> - <string name="spoken_description_question_mark" msgid="7074097784255379666">"Imaki yombuzo."</string> - <string name="spoken_description_double_quote" msgid="5485320575389905967">"Ukusho kabili"</string> - <string name="spoken_description_single_quote" msgid="4451320362665463938">"Isibizo esisodwa"</string> <string name="spoken_description_dot" msgid="40711082435231673">"Icashazi"</string> - <string name="spoken_description_square_root" msgid="190595160284757811">"Impande yesikwele"</string> - <string name="spoken_description_pi" msgid="4554418247799952239">"Pi"</string> - <string name="spoken_description_delta" msgid="3607948313655721579">"i-Delta"</string> - <string name="spoken_description_trademark" msgid="475877774077871369">"Uphawu lomkhiqizo"</string> - <string name="spoken_description_care_of" msgid="7492800237237796530">"Ukunakekela ko"</string> - <string name="spoken_description_star" msgid="1009742725387231977">"Inkanyezi"</string> - <string name="spoken_description_pound" msgid="5530577649206922631">"Iphawundi"</string> - <string name="spoken_description_ellipsis" msgid="1687670869947652062">"Ellipsis"</string> - <string name="spoken_description_low_double_quote" msgid="3551394572784840975">"Isilinganiso esikabili esiphansi"</string> <string name="voice_warning_title" msgid="4419354150908395008">"Okufakwa ngezwi"</string> <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Okufakwa ngezwi akusekelwa olimini lwakho, kodwa kuyasebenza nge-English."</string> <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Okufakwayo ngezwi kusebenzisa ukufanisa izwi kwe-Google. "<a href="http://m.google.com/privacy">"Inqubomgomo Yobumfihlo Yefoni"</a>" iyasebenza."</string> @@ -144,7 +128,6 @@ <string name="prefs_enable_log" msgid="6620424505072963557">"Vumela impendulo yomsebenzisi"</string> <string name="prefs_description_log" msgid="5827825607258246003">"Siza ukuthuthukisa lo mhleli wendlela yokufakwa ngokusithumela ngokuzenzakalela izibalo zokusetshenziswa nokukhubeka ku-Google."</string> <string name="keyboard_layout" msgid="8451164783510487501">"Indikimba yekhibhodi"</string> - <string name="subtype_de_qwerty" msgid="3358900499589259491">"i-QWERTY yesi-German"</string> <string name="subtype_en_GB" msgid="88170601942311355">"i-English(UK)"</string> <string name="subtype_en_US" msgid="6160452336634534239">"i-English (US)"</string> <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Imodi yesitadi yokusebenziseka"</string> diff --git a/java/res/values/additional-proximitychars.xml b/java/res/values/additional-proximitychars.xml new file mode 100644 index 000000000..03d10d5d8 --- /dev/null +++ b/java/res/values/additional-proximitychars.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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-array name="additional_proximitychars"> + </string-array> +</resources> diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index 0c9ca4f4a..2dea8fbb4 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -18,15 +18,18 @@ <declare-styleable name="KeyboardTheme"> <!-- Keyboard style --> <attr name="keyboardStyle" format="reference" /> + <!-- TODO: Get rid of latinKeyboardStyle --> <!-- LatinKeyboard style --> <attr name="latinKeyboardStyle" format="reference" /> <!-- KeyboardView style --> <attr name="keyboardViewStyle" format="reference" /> - <!-- MiniKeyboard style --> - <attr name="miniKeyboardStyle" format="reference" /> - <!-- MiniKeyboardView style --> - <attr name="miniKeyboardViewStyle" format="reference" /> - <attr name="miniKeyboardPanelStyle" format="reference" /> + <!-- LatinKeyboardView style --> + <attr name="latinKeyboardViewStyle" format="reference" /> + <!-- MoreKeysKeyboard style --> + <attr name="moreKeysKeyboardStyle" format="reference" /> + <!-- MoreKeysKeyboardView style --> + <attr name="moreKeysKeyboardViewStyle" format="reference" /> + <attr name="moreKeysKeyboardPanelStyle" format="reference" /> <!-- Suggestions strip style --> <attr name="suggestionsStripBackgroundStyle" format="reference" /> <attr name="suggestionsViewStyle" format="reference" /> @@ -57,16 +60,16 @@ <attr name="keyHintLetterRatio" format="float" /> <!-- Size of the text for hint label, in the proportion of key height. --> <attr name="keyHintLabelRatio" format="float" /> - <!-- Size of the text for upper case letter, in the proportion of key height. --> - <attr name="keyUppercaseLetterRatio" format="float" /> + <!-- Size of the text for shifted letter hint, in the proportion of key height. --> + <attr name="keyShiftedLetterHintRatio" format="float" /> <!-- Horizontal padding of left/right aligned key label to the edge of the key. --> <attr name="keyLabelHorizontalPadding" format="dimension" /> <!-- Top and right padding of hint letter to the edge of the key.--> <attr name="keyHintLetterPadding" format="dimension" /> <!-- Bottom padding of popup hint letter "..." to the edge of the key.--> <attr name="keyPopupHintLetterPadding" format="dimension" /> - <!-- Top and right padding of upper case letter to the edge of the key.--> - <attr name="keyUppercaseLetterPadding" format="dimension" /> + <!-- Top and right padding of shifted letter hint to the edge of the key.--> + <attr name="keyShiftedLetterHintPadding" format="dimension" /> <!-- Color to use for the label in a key. --> <attr name="keyTextColor" format="color" /> @@ -76,9 +79,9 @@ <attr name="keyHintLetterColor" format="color" /> <!-- Key hint label color --> <attr name="keyHintLabelColor" format="color" /> - <!-- Upper case letter colors --> - <attr name="keyUppercaseLetterInactivatedColor" format="color" /> - <attr name="keyUppercaseLetterActivatedColor" format="color" /> + <!-- Shifted letter hint colors --> + <attr name="keyShiftedLetterHintInactivatedColor" format="color" /> + <attr name="keyShiftedLetterHintActivatedColor" format="color" /> <!-- Layout resource for key press feedback.--> <attr name="keyPreviewLayout" format="reference" /> @@ -100,6 +103,8 @@ <attr name="keyPreviewHeight" format="dimension" /> <!-- Size of the text for key press feedback popup, int the proportion of key height --> <attr name="keyPreviewTextRatio" format="float" /> + <!-- Delay after key releasing and key press feedback dismissing in millisecond --> + <attr name="keyPreviewLingerTimeout" format="integer" /> <!-- Amount to offset the touch Y coordinate by, for bias correction. --> <attr name="verticalCorrection" format="dimension" /> @@ -120,6 +125,37 @@ </attr> </declare-styleable> + <declare-styleable name="LatinKeyboardView"> + <attr name="autoCorrectionSpacebarLedEnabled" format="boolean" /> + <attr name="autoCorrectionSpacebarLedIcon" format="reference" /> + <!-- Size of the text for spacebar language label, in the proportion of key height. --> + <attr name="spacebarTextRatio" format="fraction" /> + <attr name="spacebarTextColor" format="color" /> + <attr name="spacebarTextShadowColor" format="color" /> + <!-- Key detection hysteresis distance. --> + <attr name="keyHysteresisDistance" format="dimension" /> + <!-- Touch noise threshold time in millisecond --> + <attr name="touchNoiseThresholdTime" format="integer" /> + <!-- Touch noise threshold distance in millimeter --> + <attr name="touchNoiseThresholdDistance" format="dimension" /> + <!-- Sliding key input enable --> + <attr name="slidingKeyInputEnable" format="boolean" /> + <!-- Key repeat start timeout --> + <attr name="keyRepeatStartTimeout" format="integer" /> + <!-- Key repeat interval in millisecond. --> + <attr name="keyRepeatInterval" format="integer" /> + <!-- Long press timeout of letter key in millisecond. --> + <attr name="longPressKeyTimeout" format="integer" /> + <!-- Long press timeout of shift key in millisecond. --> + <attr name="longPressShiftKeyTimeout" format="integer" /> + <!-- Long press timeout of space key in millisecond. --> + <attr name="longPressSpaceKeyTimeout" format="integer" /> + <!-- Ignore special key timeout while typing in millisecond. --> + <attr name="ignoreSpecialKeyTimeout" format="integer" /> + <!-- More keys keyboard will shown at touched point. --> + <attr name="showMoreKeysKeyboardAtTouchedPoint" format="boolean" /> + </declare-styleable> + <declare-styleable name="SuggestionsView"> <attr name="suggestionStripOption" format="integer"> <!-- This should be aligned with SuggestionsViewParams.AUTO_CORRECT_* and etc. --> @@ -127,9 +163,11 @@ <flag name="autoCorrectUnderline" value="0x02" /> <flag name="validTypedWordBold" value="0x04" /> </attr> + <attr name="colorValidTypedWord" format="color" /> <attr name="colorTypedWord" format="color" /> <attr name="colorAutoCorrect" format="color" /> <attr name="colorSuggested" format="color" /> + <attr name="alphaValidTypedWord" format="integer" /> <attr name="alphaTypedWord" format="integer" /> <attr name="alphaAutoCorrect" format="integer" /> <attr name="alphaSuggested" format="integer" /> @@ -164,10 +202,6 @@ <attr name="verticalGap" format="dimension|fraction" /> <!-- More keys keyboard layout template --> <attr name="moreKeysTemplate" format="reference" /> - <!-- Locale of the keyboard layout --> - <attr name="keyboardLocale" format="string" /> - <!-- True if the keyboard is Right-To-Left --> - <attr name="isRtlKeyboard" format="boolean" /> <!-- Icon set for key top and key preview. --> <attr name="iconShiftKey" format="reference" /> <attr name="iconDeleteKey" format="reference" /> @@ -178,15 +212,25 @@ <attr name="iconTabKey" format="reference" /> <attr name="iconShortcutKey" format="reference" /> <attr name="iconShortcutForLabel" format="reference" /> - <attr name="iconShiftedShiftKey" format="reference" /> + <attr name="iconSpaceKeyForNumberLayout" format="reference" /> + <attr name="iconShiftKeyShifted" format="reference" /> + <attr name="iconDisabledShortcutKey" format="reference" /> <attr name="iconPreviewTabKey" format="reference" /> </declare-styleable> <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" /> + <!-- The keys to display in the more keys keyboard in addition to moreKeys. + The additional more keys are inserted at the '%' markers in the moreKeys if any. + They are inserted at the head of moreKeys if none. + If there are remaining entries of additionalMoreKeys even after all '%' markers have + been replaced, those remaining entries are appended at the end of moreKeys. --> + <attr name="additionalMoreKeys" format="string" /> <!-- Maximum column of more keys keyboard --> <attr name="maxMoreKeysColumn" format="integer" /> <attr name="backgroundType" format="enum"> @@ -194,19 +238,26 @@ <enum name="normal" value="0" /> <enum name="functional" value="1" /> <enum name="action" value="2" /> - <enum name="sticky" value="3" /> + <enum name="stickyOff" value="3" /> + <enum name="stickyOn" value="4" /> + </attr> + <!-- 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" /> + <flag name="enableLongPress" value="0x08" /> </attr> - <!-- Whether long-pressing on this key will make it repeat. --> - <attr name="isRepeatable" format="boolean" /> <!-- 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" /> @@ -216,15 +267,24 @@ <flag name="followKeyLetterRatio" value="0x80" /> <flag name="followKeyHintLabelRatio" value="0x100" /> <flag name="hasPopupHint" value="0x200" /> - <flag name="hasUppercaseLetter" value="0x400" /> + <flag name="hasShiftedLetterHint" value="0x400" /> <flag name="hasHintLabel" value="0x800" /> <flag name="withIconLeft" value="0x1000" /> <flag name="withIconRight" value="0x2000" /> <flag name="autoXScale" value="0x4000" /> + <!-- If true, character case of code, altCode, moreKeys, keyOutputText, keyLabel, + or keyHintLabel will never be subject to change. --> + <flag name="preserveCase" value="0x8000" /> + <!-- If true, use keyShiftedLetterHintActivatedColor for the shifted letter hint and + keyTextInactivatedColor for the primary key top label. --> + <flag name="shiftedLetterActivated" value="0x10000" /> + <!-- If true, use EditorInfo.actionLabel for the key label. --> + <flag name="fromCustomActionLabel" value="0x20000" /> </attr> <!-- The icon to display on the key instead of the label. --> <attr name="keyIcon" format="enum"> - <!-- This should be aligned with KeyboardIcons.ICON_* --> + <!-- This should be aligned with the KeyboardIconsSet.ICON_* --> + <enum name="iconUndefined" value="0" /> <enum name="iconShiftKey" value="1" /> <enum name="iconDeleteKey" value="2" /> <enum name="iconSettingsKey" value="3" /> @@ -234,21 +294,21 @@ <enum name="iconTabKey" value="7" /> <enum name="iconShortcutKey" value="8" /> <enum name="iconShortcutForLabel" value="9" /> + <enum name="iconSpaceKeyForNumberLayout" value="10" /> + <enum name="iconShiftKeyShifted" value="11" /> </attr> - <!-- Shift key icon for shifted state --> - <attr name="keyIconShifted" format="enum"> - <!-- This should be aligned with KeyboardIcons.ICON_SHIFTED_* --> - <enum name="iconShiftedShiftKey" value="10" /> + <!-- The icon for disabled key --> + <attr name="keyIconDisabled" format="enum"> + <!-- This should be aligned with the KeyboardIconsSet.ICON_* --> + <enum name="iconDisabledShortcutKey" value="12" /> </attr> <!-- The icon to show in the popup preview. --> <attr name="keyIconPreview" format="enum"> - <!-- This should be aligned with KeyboardIcons.ICON_PREVIEW_* --> - <enum name="iconPreviewTabKey" value="11" /> + <!-- This should be aligned with the KeyboardIconsSet.ICON_* --> + <enum name="iconPreviewTabKey" value="13" /> </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" /> @@ -273,6 +333,19 @@ </declare-styleable> <declare-styleable name="Keyboard_Case"> + <!-- This should be aligned with KeyboardSet_Element's elementName. --> + <attr name="keyboardSetElement" format="enum|string"> + <enum name="alphabet" value="0" /> + <enum name="alphabetManualShifted" value="1" /> + <enum name="alphabetAutomaticShifted" value="2" /> + <enum name="alphabetShiftLocked" value="3" /> + <enum name="alphabetShiftLockShifted" value="4" /> + <enum name="symbols" value="5" /> + <enum name="symbolsShifted" value="6" /> + <enum name="phone" value="7" /> + <enum name="phoneSymbols" value="8" /> + <enum name="number" value="9" /> + </attr> <!-- This should be aligned with KeyboardId.MODE_* --> <attr name="mode" format="enum|string"> <enum name="text" value="0" /> @@ -295,6 +368,7 @@ <attr name="clobberSettingsKey" format="boolean" /> <attr name="shortcutKeyEnabled" format="boolean" /> <attr name="hasShortcutKey" format="boolean" /> + <attr name="isMultiLine" format="boolean" /> <attr name="imeAction" format="enum"> <!-- This should be aligned with EditorInfo.IME_ACTION_* --> <enum name="actionUnspecified" value="0" /> @@ -305,6 +379,8 @@ <enum name="actionNext" value="5" /> <enum name="actionDone" value="6" /> <enum name="actionPrevious" value="7" /> + <!-- This should be aligned with KeyboardId.IME_ACTION_* --> + <enum name="actionCustomLabel" value="0x100" /> </attr> <attr name="localeCode" format="string" /> <attr name="languageCode" format="string" /> @@ -316,11 +392,25 @@ <attr name="parentStyle" format="string" /> </declare-styleable> - <declare-styleable name="LatinKeyboard"> - <attr name="autoCorrectionSpacebarLedEnabled" format="boolean" /> - <attr name="autoCorrectionSpacebarLedIcon" format="reference" /> - <attr name="disabledShortcutIcon" format="reference" /> - <attr name="spacebarTextColor" format="color" /> - <attr name="spacebarTextShadowColor" format="color" /> + <declare-styleable name="KeyboardSet"> + <!-- Locale of the keyboard layouts --> + <attr name="keyboardLocale" format="string" /> + </declare-styleable> + + <declare-styleable name="KeyboardSet_Element"> + <!-- This should be aligned with KeyboardId.ELEMENT_* --> + <attr name="elementName" format="enum"> + <enum name="alphabet" value="0" /> + <enum name="alphabetManualShifted" value="1" /> + <enum name="alphabetAutomaticShifted" value="2" /> + <enum name="alphabetShiftLocked" value="3" /> + <enum name="alphabetShiftLockShifted" value="4" /> + <enum name="symbols" value="5" /> + <enum name="symbolsShifted" value="6" /> + <enum name="phone" value="7" /> + <enum name="phoneSymbols" value="8" /> + <enum name="number" value="9" /> + </attr> + <attr name="elementKeyboard" format="reference"/> </declare-styleable> </resources> diff --git a/java/res/values/config.xml b/java/res/values/config.xml index 3f676ab25..cb13ba30b 100644 --- a/java/res/values/config.xml +++ b/java/res/values/config.xml @@ -25,9 +25,8 @@ <bool name="config_enable_show_voice_key_option">true</bool> <bool name="config_enable_show_popup_on_keypress_option">true</bool> <bool name="config_enable_bigram_suggestions_option">true</bool> - <bool name="config_enable_usability_study_mode_option">false</bool> - <bool name="config_sliding_key_input_enabled">true</bool> - <bool name="config_digit_more_keys_enabled">true</bool> + <!-- TODO: Disable the following configuration for production. --> + <bool name="config_enable_usability_study_mode_option">true</bool> <!-- Whether or not Popup on key press is enabled by default --> <bool name="config_default_popup_preview">true</bool> <!-- Default value for bigram suggestion: while showing suggestions for a word should we weigh @@ -38,9 +37,6 @@ <bool name="config_default_bigram_prediction">false</bool> <bool name="config_default_sound_enabled">false</bool> <bool name="config_default_vibration_enabled">true</bool> - <bool name="config_auto_correction_spacebar_led_enabled">false</bool> - <!-- Showing mini keyboard, just above the touched point if true, aligned to the key if false --> - <bool name="config_show_mini_keyboard_at_touched_point">false</bool> <!-- The language is never displayed if == 0, always displayed if < 0 --> <integer name="config_delay_before_fadeout_language_on_spacebar">1200</integer> <integer name="config_delay_update_suggestions">100</integer> @@ -48,27 +44,40 @@ <integer name="config_delay_update_shift_state">100</integer> <integer name="config_duration_of_fadeout_language_on_spacebar">50</integer> <integer name="config_final_fadeout_percentage_of_language_on_spacebar">50</integer> - <integer name="config_delay_before_preview">0</integer> - <integer name="config_delay_after_preview">70</integer> - <integer name="config_mini_keyboard_fadein_anim_time">0</integer> - <integer name="config_mini_keyboard_fadeout_anim_time">100</integer> - <integer name="config_delay_before_key_repeat_start">400</integer> - <integer name="config_key_repeat_interval">50</integer> + <integer name="config_more_keys_keyboard_fadein_anim_time">0</integer> + <integer name="config_more_keys_keyboard_fadeout_anim_time">100</integer> <integer name="config_keyboard_grid_width">32</integer> <integer name="config_keyboard_grid_height">16</integer> + <integer name="config_double_spaces_turn_into_period_timeout">1100</integer> + <!-- This configuration is the index of the array {@link KeyboardSwitcher.KEYBOARD_THEMES}. --> + <string name="config_default_keyboard_theme_id" translatable="false">5</string> + <integer name="config_max_more_keys_column">5</integer> + <!-- + Configuration for KeyboardView + --> + <integer name="config_key_preview_linger_timeout">70</integer> + <!-- + Configuration for LatinKeyboardView + --> + <dimen name="config_key_hysteresis_distance">0.05in</dimen> + <integer name="config_touch_noise_threshold_time">40</integer> + <dimen name="config_touch_noise_threshold_distance">2.0mm</dimen> + <bool name="config_sliding_key_input_enabled">true</bool> + <integer name="config_key_repeat_start_timeout">400</integer> + <integer name="config_key_repeat_interval">50</integer> <integer name="config_long_press_key_timeout">400</integer> <!-- Long pressing shift will invoke caps-lock if > 0, never invoke caps-lock if == 0 --> <integer name="config_long_press_shift_key_timeout">1200</integer> <!-- Long pressing space will invoke IME switcher if > 0, never invoke IME switcher if == 0 --> - <integer name="config_long_press_space_key_timeout">@integer/config_long_press_key_timeout</integer> - <integer name="config_touch_noise_threshold_millis">40</integer> - <integer name="config_double_spaces_turn_into_period_timeout">1100</integer> + <integer name="config_long_press_space_key_timeout"> + @integer/config_long_press_key_timeout</integer> <integer name="config_ignore_special_key_timeout">700</integer> - <dimen name="config_touch_noise_threshold_distance">2.0mm</dimen> - <!-- This configuration is the index of the array {@link KeyboardSwitcher.KEYBOARD_THEMES}. --> - <string name="config_default_keyboard_theme_id" translatable="false">5</string> - <string name="config_text_size_of_language_on_spacebar" translatable="false">small</string> - <integer name="config_max_more_keys_column">5</integer> + <!-- Showing more keys keyboard, just above the touched point if true, aligned to the key if + false --> + <bool name="config_show_more_keys_keyboard_at_touched_point">false</bool> + <!-- + Configuration for auto correction + --> <string-array name="auto_correction_threshold_values" translatable="false"> <!-- Off, When auto correction setting is Off, this value is not used. --> <item></item> @@ -81,9 +90,11 @@ 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 any dictionary lookup to be offered as a suggestion by the spell checker --> + <!-- 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. 0 = "mdpi phone screen" diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml index 352141ca6..41a297902 100644 --- a/java/res/values/dimens.xml +++ b/java/res/values/dimens.xml @@ -26,8 +26,8 @@ <dimen name="popup_key_height">0.330in</dimen> - <dimen name="mini_keyboard_horizontal_edges_padding">16dip</dimen> - <dimen name="mini_keyboard_key_horizontal_padding">8dip</dimen> + <dimen name="more_keys_keyboard_horizontal_edges_padding">16dip</dimen> + <dimen name="more_keys_keyboard_key_horizontal_padding">8dip</dimen> <fraction name="keyboard_top_padding">1.556%p</fraction> <fraction name="keyboard_bottom_padding">4.669%p</fraction> @@ -48,13 +48,13 @@ <fraction name="keyboard_bottom_padding_ics">4.669%p</fraction> <fraction name="key_bottom_gap_ics">6.127%p</fraction> <fraction name="key_horizontal_gap_ics">1.739%p</fraction> - <dimen name="mini_keyboard_horizontal_edges_padding_ics">4dip</dimen> + <dimen name="more_keys_keyboard_horizontal_edges_padding_ics">4dip</dimen> <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. --> <!-- popup_key_height x 1.2 --> - <dimen name="mini_keyboard_slide_allowance">0.396in</dimen> + <dimen name="more_keys_keyboard_slide_allowance">0.396in</dimen> <!-- popup_key_height x -1.0 --> - <dimen name="mini_keyboard_vertical_correction">-0.330in</dimen> + <dimen name="more_keys_keyboard_vertical_correction">-0.330in</dimen> <!-- We use "inch", not "dip" because this value tries dealing with physical distance related to user's finger. --> <dimen name="keyboard_vertical_correction">0.0in</dimen> @@ -66,6 +66,7 @@ <fraction name="key_hint_label_ratio">44%</fraction> <fraction name="key_uppercase_letter_ratio">35%</fraction> <fraction name="key_preview_text_ratio">82%</fraction> + <fraction name="spacebar_text_ratio">33.735%</fraction> <dimen name="key_preview_height">80sp</dimen> <dimen name="key_preview_offset">0.1in</dimen> @@ -95,6 +96,4 @@ <dimen name="more_suggestions_hint_text_size">27dip</dimen> <integer name="suggestions_count_in_strip">3</integer> <integer name="center_suggestion_percentile">36</integer> - - <dimen name="key_hysteresis_distance">0.05in</dimen> </resources> diff --git a/java/res/values/donottranslate-more-keys.xml b/java/res/values/donottranslate-more-keys.xml index 6c7753999..57a6d6bda 100644 --- a/java/res/values/donottranslate-more-keys.xml +++ b/java/res/values/donottranslate-more-keys.xml @@ -19,39 +19,44 @@ --> <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_e"></string> + <string name="more_keys_for_i"></string> + <string name="more_keys_for_o"></string> + <string name="more_keys_for_u"></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_q">1</string> - <string name="more_keys_for_w">2</string> + <string name="more_keys_for_y"></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_r"></string> + <string name="more_keys_for_t"></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_p">0</string> <string name="more_keys_for_v"></string> + <string name="keylabel_for_scandinavia_row1_11"></string> <string name="keylabel_for_scandinavia_row2_10"></string> <string name="keylabel_for_scandinavia_row2_11"></string> <string name="more_keys_for_scandinavia_row2_10"></string> <string name="more_keys_for_scandinavia_row2_11"></string> - <string name="more_keys_for_cyrillic_e"></string> - <string name="more_keys_for_cyrillic_soft_sign"></string> - <string name="more_keys_for_cyrillic_ha"></string> + <string name="keylabel_for_slavic_shcha">щ</string> + <string name="keylabel_for_slavic_yery">ы</string> + <string name="keylabel_for_slavic_i">и</string> + <string name="more_keys_for_slavic_u"></string> + <string name="more_keys_for_slavic_ye"></string> + <string name="more_keys_for_slavic_en"></string> + <string name="more_keys_for_slavic_ha">ъ</string> + <string name="more_keys_for_slavic_yery"></string> + <string name="more_keys_for_slavic_o"></string> + <string name="more_keys_for_slavic_soft_sign">ъ</string> <string name="more_keys_for_currency_dollar">¢,£,€,¥,₱</string> <string name="more_keys_for_currency_euro">¢,£,$,¥,₱</string> <string name="more_keys_for_currency_pound">¢,$,€,¥,₱</string> <string name="more_keys_for_currency_general">¢,$,€,£,¥,₱</string> - <string name="more_keys_for_smiley">":-)|:-) ,:-(|:-( ,;-)|;-) ,:-P|:-P ,=-O|=-O ,:-*|:-* ,:O|:O ,B-)|B-) ,:-$|:-$ ,:-!|:-! ,:-[|:-[ ,O:-)|O:-) ,:-\\\\\\\\|:-\\\\\\\\ ,:\'(|:\'( ,:-D|:-D "</string> + <string name="more_keys_for_smiley">":-)|:-) ,:-(|:-( ,;-)|;-) ,:-P|:-P ,=-O|=-O ,:-*|:-* ,:O|:O ,B-)|B-) ,:-$|:-$ ,:-!|:-! ,:-[|:-[ ,O:-)|O:-) ,:-\\\\|:-\\\\ ,:\'(|:\'( ,:-D|:-D "</string> <string name="more_keys_for_punctuation">"\\,,\?,!,:,-,\',\",(,),/,;,+,&,\@"</string> - <integer name="mini_keyboard_column_for_punctuation">7</integer> + <integer name="more_keys_keyboard_column_for_punctuation">7</integer> <string name="keyhintlabel_for_punctuation"></string> <string name="keylabel_for_popular_domain">".com"</string> <!-- popular web domains for the locale - most popular, displayed on the keyboard --> @@ -66,6 +71,16 @@ <string name="keylabel_for_symbols_8">8</string> <string name="keylabel_for_symbols_9">9</string> <string name="keylabel_for_symbols_0">0</string> + <string name="additional_more_keys_for_symbols_1"></string> + <string name="additional_more_keys_for_symbols_2"></string> + <string name="additional_more_keys_for_symbols_3"></string> + <string name="additional_more_keys_for_symbols_4"></string> + <string name="additional_more_keys_for_symbols_5"></string> + <string name="additional_more_keys_for_symbols_6"></string> + <string name="additional_more_keys_for_symbols_7"></string> + <string name="additional_more_keys_for_symbols_8"></string> + <string name="additional_more_keys_for_symbols_9"></string> + <string name="additional_more_keys_for_symbols_0"></string> <string name="more_keys_for_symbols_1">¹,½,⅓,¼,⅛</string> <string name="more_keys_for_symbols_2">²,⅔</string> <string name="more_keys_for_symbols_3">³,¾,⅜</string> @@ -83,10 +98,8 @@ <string name="keylabel_for_symbols_percent">%</string> <string name="more_keys_for_comma"></string> <string name="more_keys_for_f1"></string> - <!-- @icon/3 is iconSettingsKey --> - <string name="more_keys_for_f1_settings">\@icon/3|\@integer/key_settings</string> - <!-- @icon/7 is iconTabKey --> - <string name="more_keys_for_f1_navigate">\@icon/7|\@integer/key_tab</string> + <string name="more_keys_for_f1_settings">\@icon/settingsKey|\@integer/key_settings</string> + <string name="more_keys_for_f1_navigate">\@icon/tabKey|\@integer/key_tab</string> <string name="more_keys_for_symbols_question">¿</string> <string name="more_keys_for_symbols_semicolon"></string> <string name="more_keys_for_symbols_percent">‰</string> @@ -99,6 +112,43 @@ <string name="more_keys_for_bullet">♪,♥,♠,♦,♣</string> <string name="more_keys_for_star">†,‡,★</string> <string name="more_keys_for_plus">±</string> + <!-- The all letters need to be mirrored are found at + http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt --> + <integer name="keycode_for_left_parenthesis">0x0028</integer> + <integer name="keycode_for_right_parenthesis">0x0029</integer> <string name="more_keys_for_left_parenthesis">[,{,<</string> <string name="more_keys_for_right_parenthesis">],},></string> + <integer name="keycode_for_less_than">0x003c</integer> + <integer name="keycode_for_greater_than">0x003e</integer> + <!-- \u2264: LESS-THAN OR EQUAL TO + \u2265: GREATER-THAN EQUAL TO + \u00ab: LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + \u00bb: RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + \u2039: SINGLE LEFT-POINTING ANGLE QUOTATION MARK + \u203a: SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + The following characters don't need BIDI mirroring. + \u2018: LEFT SINGLE QUOTATION MARK + \u2019: RIGHT SINGLE QUOTATION MARK + \u201a: SINGLE LOW-9 QUOTATION MARK + \u201b: SINGLE HIGH-REVERSED-9 QUOTATION MARK + \u201c: LEFT DOUBLE QUOTATION MARK + \u201d: RIGHT DOUBLE QUOTATION MARK + \u201e: DOUBLE LOW-9 QUOTATION MARK + \u201f: DOUBLE HIGH-REVERSED-9 QUOTATION MARK --> + <string name="more_keys_for_less_than">\u2264,\u00ab,\u2039</string> + <string name="more_keys_for_greater_than">\u2265,\u00bb,\u203a</string> + <integer name="keycode_for_left_square_bracket">0x005b</integer> + <integer name="keycode_for_right_square_bracket">0x005d</integer> + <integer name="keycode_for_left_curly_bracket">0x007b</integer> + <integer name="keycode_for_right_curly_bracket">0x007d</integer> + <!-- The 4-more keys will be displayed in order of "3,1,2,4". --> + <string name="more_keys_for_single_quote">\u2019,\u201a,\u2018,\u201b</string> + <!-- Note: Neither DroidSans nor Roboto have a glyph for DOUBLE HIGH-REVERSED-9 QUOTATION MARK. --> + <!-- <string name="more_keys_for_double_quote">\u201c,\u201d,\u201e,\u201f,\u00ab,\u00bb</string> --> + <!-- The 4-more keys will be displayed in order of "3,1,2,4". --> + <string name="more_keys_for_double_quote">\u201d,\u00ab,\u201c,\u00bb</string> + <!-- Note: Neither DroidSans nor Roboto have a glyph for DOUBLE HIGH-REVERSED-9 QUOTATION MARK. --> + <!-- <string name="more_keys_for_tablet_double_quote">\u201c,\u201d,\u201e,\u201f,\u00ab,\u00bb,\u2018,\u2019,\u201a,\u201b</string> --> + <!-- The 8-more keys with maxMoreKeysColumn=4 will be displayed in order of "3,1,2,4|7,5,6,8". --> + <string name="more_keys_for_tablet_double_quote">\u201d,\u00ab,\u201c,\u00bb,\u2019,\u201a,\u2018,\u201b</string> </resources> diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml index aefaec9ef..cd5e3d8ea 100644 --- a/java/res/values/donottranslate.xml +++ b/java/res/values/donottranslate.xml @@ -19,7 +19,7 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- Symbols that are suggested between words --> - <string name="suggested_punctuations">!?,:;\u0022()\u0027-/@_</string> + <string name="suggested_punctuations">!,?,\\,,:,;,\u0022,(,),\u0027,-,/,@,_</string> <!-- Symbols that should be swapped with a magic space --> <string name="magic_space_swapping_symbols">.,;:!?)]}\u0022</string> <!-- Symbols that should strip a magic space --> @@ -120,6 +120,7 @@ <!-- Title for Latin keyboard debug settings activity / dialog --> <string name="english_ime_debug_settings">Android keyboard Debug settings</string> <string name="prefs_debug_mode">Debug Mode</string> + <string name="prefs_force_non_distinct_multitouch">Force non-distinct multitouch</string> <!-- Keyboard theme names --> <string name="layout_basic">Basic</string> @@ -161,9 +162,12 @@ <!-- Generic subtype label --> <string name="subtype_generic">%s</string> + <!-- Description for generic QWERTY keyboard subtype --> + <string name="subtype_generic_qwerty">%s (QWERTY)</string> <!-- dictionary pack package name /settings activity (for shared prefs and settings) --> <string name="dictionary_pack_package_name">com.google.android.inputmethod.latin.dictionarypack</string> <string name="dictionary_pack_settings_activity">com.google.android.inputmethod.latin.dictionarypack.DictionarySettingsActivity</string> <string name="settings_ms">ms</string> + <string name="settings_warning_researcher_mode">Attention! You are using the special keyboard for research purposes.</string> </resources> diff --git a/java/res/values/keyboard-icons-black.xml b/java/res/values/keyboard-icons-black.xml index f767cb349..1c5a5f720 100644 --- a/java/res/values/keyboard-icons-black.xml +++ b/java/res/values/keyboard-icons-black.xml @@ -30,10 +30,9 @@ <item name="iconTabKey">@drawable/sym_bkeyboard_tab</item> <item name="iconShortcutKey">@drawable/sym_bkeyboard_mic</item> <item name="iconShortcutForLabel">@drawable/sym_bkeyboard_label_mic</item> - <item name="iconShiftedShiftKey">@drawable/sym_bkeyboard_shift_locked</item> + <item name="iconSpaceKeyForNumberLayout">@drawable/sym_bkeyboard_space</item> + <item name="iconShiftKeyShifted">@drawable/sym_bkeyboard_shift_locked</item> + <item name="iconDisabledShortcutKey">@drawable/sym_bkeyboard_voice_off</item> <item name="iconPreviewTabKey">@drawable/sym_keyboard_feedback_tab</item> - <!-- LatinKeyboard icons --> - <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item> - <item name="disabledShortcutIcon">@drawable/sym_bkeyboard_voice_off</item> </style> </resources> diff --git a/java/res/values/keyboard-icons-ics.xml b/java/res/values/keyboard-icons-ics.xml index f1021433d..f68be5f1e 100644 --- a/java/res/values/keyboard-icons-ics.xml +++ b/java/res/values/keyboard-icons-ics.xml @@ -23,16 +23,15 @@ <item name="iconShiftKey">@drawable/sym_keyboard_shift_holo</item> <item name="iconDeleteKey">@drawable/sym_keyboard_delete_holo</item> <item name="iconSettingsKey">@drawable/sym_keyboard_settings_holo</item> - <item name="iconSpaceKey">@drawable/sym_keyboard_space_holo</item> + <item name="iconSpaceKey">@null</item> <item name="iconReturnKey">@drawable/sym_keyboard_return_holo</item> <item name="iconSearchKey">@drawable/sym_keyboard_search_holo</item> <item name="iconTabKey">@drawable/sym_keyboard_tab_holo</item> <item name="iconShortcutKey">@drawable/sym_keyboard_voice_holo</item> <item name="iconShortcutForLabel">@drawable/sym_keyboard_label_mic_holo</item> - <item name="iconShiftedShiftKey">@drawable/sym_keyboard_shift_locked_holo</item> + <item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space_holo</item> + <item name="iconShiftKeyShifted">@drawable/sym_keyboard_shift_locked_holo</item> + <item name="iconDisabledShortcutKey">@drawable/sym_keyboard_voice_off_holo</item> <item name="iconPreviewTabKey">@drawable/sym_keyboard_feedback_tab</item> - <!-- LatinKeyboard icons --> - <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led_holo</item> - <item name="disabledShortcutIcon">@drawable/sym_keyboard_voice_off_holo</item> </style> </resources> diff --git a/java/res/values/keyboard-icons-white.xml b/java/res/values/keyboard-icons-white.xml index 07ece66b1..35197a1c0 100644 --- a/java/res/values/keyboard-icons-white.xml +++ b/java/res/values/keyboard-icons-white.xml @@ -26,10 +26,10 @@ <item name="iconTabKey">@drawable/sym_keyboard_tab</item> <item name="iconShortcutKey">@drawable/sym_keyboard_mic</item> <item name="iconShortcutForLabel">@drawable/sym_keyboard_label_mic</item> - <item name="iconShiftedShiftKey">@drawable/sym_keyboard_shift_locked</item> + <item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space</item> + <item name="iconShiftKeyShifted">@drawable/sym_keyboard_shift_locked</item> + <!-- TODO: Needs non-holo disabled shortcut icon drawable --> + <item name="iconDisabledShortcutKey">@drawable/sym_keyboard_voice_off_holo</item> <item name="iconPreviewTabKey">@drawable/sym_keyboard_feedback_tab</item> - <!-- LatinKeyboard icons --> - <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item> - <item name="disabledShortcutIcon">@drawable/sym_keyboard_voice_off_holo</item> </style> </resources> diff --git a/java/res/values/keycodes.xml b/java/res/values/keycodes.xml index 59cc07531..c85c02263 100644 --- a/java/res/values/keycodes.xml +++ b/java/res/values/keycodes.xml @@ -21,11 +21,14 @@ <resources> <!-- These code should be aligned with Keyboard.CODE_*. --> <integer name="key_tab">9</integer> - <integer name="key_return">10</integer> + <integer name="key_enter">10</integer> <integer name="key_space">32</integer> <integer name="key_shift">-1</integer> <integer name="key_switch_alpha_symbol">-2</integer> - <integer name="key_delete">-5</integer> - <integer name="key_settings">-6</integer> - <integer name="key_shortcut">-7</integer> + <integer name="key_output_text">-3</integer> + <integer name="key_delete">-4</integer> + <integer name="key_settings">-5</integer> + <integer name="key_shortcut">-6</integer> + <integer name="key_action_enter">-7</integer> + <integer name="key_unspecified">-9</integer> </resources> diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index e00547a62..1e8b7db96 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -20,6 +20,8 @@ <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- Title for Latin keyboard --> <string name="english_ime_name">Android keyboard</string> + <!-- Application name for opensource Android keyboard. AOSP(Android Open Source Project) should not be translated. --> + <string name="aosp_android_keyboard_ime_name">Android keyboard (AOSP)</string> <!-- Title for Latin keyboard settings activity / dialog --> <string name="english_ime_settings">Android keyboard settings</string> <!-- Title for Latin keyboard input options dialog [CHAR LIMIT=25] --> @@ -31,11 +33,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> @@ -126,6 +128,8 @@ <string name="label_go_key">Go</string> <!-- Label for soft enter key when it performs NEXT action. Must be short to fit on key! [CHAR LIMIT=5] --> <string name="label_next_key">Next</string> + <!-- Label for soft enter key when it performs PREVIOUS action. Must be short to fit on key! [CHAR LIMIT=5] --> + <string name="label_previous_key">Prev</string> <!-- Label for soft enter key when it performs DONE action. Must be short to fit on key! [CHAR LIMIT=5] --> <string name="label_done_key">Done</string> <!-- Label for soft enter key when it performs SEND action. Must be short to fit on key! [CHAR LIMIT=5] --> @@ -152,12 +156,12 @@ <!-- Spoken description for unknown keyboard keys. --> <string name="spoken_description_unknown">Key code %d</string> - <!-- Spoken description for the "Shift" keyboard key. --> + <!-- Spoken description for the "Shift" keyboard key when "Shift" is off. --> <string name="spoken_description_shift">Shift</string> - <!-- Spoken description for the "Shift" keyboard key's pressed state. --> - <string name="spoken_description_shift_shifted">Shift enabled</string> - <!-- Spoken description for the "Shift" keyboard key's pressed state. --> - <string name="spoken_description_caps_lock">Caps lock enabled</string> + <!-- Spoken description for the "Shift" keyboard key when "Shift" is on. --> + <string name="spoken_description_shift_shifted">Shift on (tap to disable)</string> + <!-- Spoken description for the "Shift" keyboard key when "Caps lock" is on. --> + <string name="spoken_description_caps_lock">Caps lock on (tap to disable)</string> <!-- Spoken description for the "Delete" keyboard key. --> <string name="spoken_description_delete">Delete</string> <!-- Spoken description for the "To Symbol" keyboard key. --> @@ -178,47 +182,24 @@ <string name="spoken_description_smiley">Smiley face</string> <!-- Spoken description for the "Return" keyboard key. --> <string name="spoken_description_return">Return</string> - - <!-- Spoken description for the "," keyboard key. --> - <string name="spoken_description_comma">Comma</string> - <!-- Spoken description for the "." keyboard key. --> - <string name="spoken_description_period">Period</string> - <!-- Spoken description for the "(" keyboard key. --> - <string name="spoken_description_left_parenthesis">Left parenthesis</string> - <!-- Spoken description for the ")" keyboard key. --> - <string name="spoken_description_right_parenthesis">Right parenthesis</string> - <!-- Spoken description for the ":" keyboard key. --> - <string name="spoken_description_colon">Colon</string> - <!-- Spoken description for the ";" keyboard key. --> - <string name="spoken_description_semicolon">Semicolon</string> - <!-- Spoken description for the "!" keyboard key. --> - <string name="spoken_description_exclamation_mark">Exclamation mark</string> - <!-- Spoken description for the "?" keyboard key. --> - <string name="spoken_description_question_mark">Question mark</string> - <!-- Spoken description for the """ keyboard key. --> - <string name="spoken_description_double_quote">Double quote</string> - <!-- Spoken description for the "'" keyboard key. --> - <string name="spoken_description_single_quote">Single quote</string> <!-- Spoken description for the "\u2022" (BULLET) keyboard key. --> <string name="spoken_description_dot">Dot</string> - <!-- Spoken description for the "\u221a" (SQUARE ROOT) keyboard key. --> - <string name="spoken_description_square_root">Square root</string> - <!-- Spoken description for the "\u03C0" (GREEK SMALL LETTER PI) keyboard key. --> - <string name="spoken_description_pi">Pi</string> - <!-- Spoken description for the "\u0394" (GREEK CAPITAL LETTER DELTA) keyboard key. --> - <string name="spoken_description_delta">Delta</string> - <!-- Spoken description for the "\u2122" (TRADE MARK SIGN) keyboard key. --> - <string name="spoken_description_trademark">Trademark</string> - <!-- Spoken description for the "\u2105" (CARE OF) keyboard key. --> - <string name="spoken_description_care_of">Care of</string> - <!-- Spoken description for the "*" keyboard key. --> - <string name="spoken_description_star">Star</string> - <!-- Spoken description for the "#" keyboard key. --> - <string name="spoken_description_pound">Pound</string> - <!-- Spoken description for the "\u2026" (HORIZONTAL ELLIPSIS) keyboard key. --> - <string name="spoken_description_ellipsis">Ellipsis</string> - <!-- Spoken description for the "\u201E" (DOUBLE LOW-9 QUOTATION MARK) keyboard key. --> - <string name="spoken_description_low_double_quote">Low double quote</string> + + <!-- Spoken feedback after turning "Shift" mode on. --> + <string name="spoken_description_shiftmode_on">Shift enabled</string> + <!-- Spoken feedback after turning "Caps lock" mode on. --> + <string name="spoken_description_shiftmode_locked">Caps lock enabled</string> + <!-- Spoken feedback after turning "Shift" mode off. --> + <string name="spoken_description_shiftmode_off">Shift disabled</string> + + <!-- Spoken feedback after changing to the symbols keyboard. --> + <string name="spoken_description_mode_symbol">Symbols mode</string> + <!-- Spoken feedback after changing to the alphanumeric keyboard. --> + <string name="spoken_description_mode_alpha">Letters mode</string> + <!-- Spoken feedback after changing to the phone dialer keyboard. --> + <string name="spoken_description_mode_phone">Phone mode</string> + <!-- Spoken feedback after changing to the shifted phone dialer (symbols) keyboard. --> + <string name="spoken_description_mode_phone_shift">Phone symbols mode</string> <!-- Voice related labels --> @@ -333,8 +314,6 @@ <!-- Title of the item to change the keyboard theme [CHAR LIMIT=20]--> <string name="keyboard_layout">Keyboard theme</string> - <!-- Description for German QWERTY keyboard subtype [CHAR LIMIT=22] --> - <string name="subtype_de_qwerty">German QWERTY</string> <!-- Description for English (United Kingdom) keyboard subtype [CHAR LIMIT=22] --> <string name="subtype_en_GB">English (UK)</string> <!-- Description for English (United States) keyboard subtype [CHAR LIMIT=22] --> diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml index 43aa58388..b9e8b26a3 100644 --- a/java/res/values/styles.xml +++ b/java/res/values/styles.xml @@ -23,7 +23,7 @@ <item name="keyboardHeight">@dimen/keyboardHeight</item> <item name="maxKeyboardHeight">@fraction/maxKeyboardHeight</item> <item name="minKeyboardHeight">@fraction/minKeyboardHeight</item> - <item name="moreKeysTemplate">@xml/kbd_mini_keyboard_template</item> + <item name="moreKeysTemplate">@xml/kbd_more_keys_keyboard_template</item> <item name="keyboardTopPadding">@fraction/keyboard_top_padding</item> <item name="keyboardBottomPadding">@fraction/keyboard_bottom_padding</item> <item name="keyboardHorizontalEdgesPadding">@fraction/keyboard_horizontal_edges_padding</item> @@ -31,12 +31,6 @@ <item name="verticalGap">@fraction/key_bottom_gap</item> <item name="maxMoreKeysColumn">@integer/config_max_more_keys_column</item> </style> - <style name="LatinKeyboard"> - <item name="autoCorrectionSpacebarLedEnabled">@bool/config_auto_correction_spacebar_led_enabled - </item> - <item name="spacebarTextColor">#FFC0C0C0</item> - <item name="spacebarTextShadowColor">#80000000</item> - </style> <style name="KeyboardView"> <item name="android:background">@drawable/keyboard_background</item> <item name="keyBackground">@drawable/btn_keyboard_key</item> @@ -45,18 +39,18 @@ <item name="keyLabelRatio">@fraction/key_label_ratio</item> <item name="keyHintLetterRatio">@fraction/key_hint_letter_ratio</item> <item name="keyHintLabelRatio">@fraction/key_hint_label_ratio</item> - <item name="keyUppercaseLetterRatio">@fraction/key_uppercase_letter_ratio</item> + <item name="keyShiftedLetterHintRatio">@fraction/key_uppercase_letter_ratio</item> <item name="keyTextStyle">normal</item> <item name="keyTextColor">#FFFFFFFF</item> <item name="keyTextInactivatedColor">#FFFFFFFF</item> <item name="keyHintLetterColor">#80000000</item> <item name="keyHintLabelColor">#E0E0E4E5</item> - <item name="keyUppercaseLetterInactivatedColor">#66E0E4E5</item> - <item name="keyUppercaseLetterActivatedColor">#CCE0E4E5</item> + <item name="keyShiftedLetterHintInactivatedColor">#66E0E4E5</item> + <item name="keyShiftedLetterHintActivatedColor">#CCE0E4E5</item> <item name="keyLabelHorizontalPadding">@dimen/key_label_horizontal_padding</item> <item name="keyHintLetterPadding">@dimen/key_hint_letter_padding</item> <item name="keyPopupHintLetterPadding">@dimen/key_popup_hint_letter_padding</item> - <item name="keyUppercaseLetterPadding">@dimen/key_uppercase_letter_padding</item> + <item name="keyShiftedLetterHintPadding">@dimen/key_uppercase_letter_padding</item> <item name="keyPreviewLayout">@layout/key_preview</item> <item name="keyPreviewBackground">@drawable/keyboard_key_feedback</item> <item name="keyPreviewLeftBackground">@null</item> @@ -65,14 +59,36 @@ <item name="keyPreviewOffset">@dimen/key_preview_offset</item> <item name="keyPreviewHeight">@dimen/key_preview_height</item> <item name="keyPreviewTextRatio">@fraction/key_preview_text_ratio</item> - <item name="moreKeysLayout">@layout/mini_keyboard</item> + <item name="keyPreviewLingerTimeout">@integer/config_key_preview_linger_timeout</item> + <item name="moreKeysLayout">@layout/more_keys_keyboard</item> <item name="verticalCorrection">@dimen/keyboard_vertical_correction</item> <item name="shadowColor">#BB000000</item> <item name="shadowRadius">2.75</item> <item name="backgroundDimAmount">0.5</item> + <!-- Common attributes of LatinKeyboardView --> + <item name="keyHysteresisDistance">@dimen/config_key_hysteresis_distance</item> + <item name="touchNoiseThresholdTime">@integer/config_touch_noise_threshold_time</item> + <item name="touchNoiseThresholdDistance">@dimen/config_touch_noise_threshold_distance</item> + <item name="slidingKeyInputEnable">@bool/config_sliding_key_input_enabled</item> + <item name="keyRepeatStartTimeout">@integer/config_key_repeat_start_timeout</item> + <item name="keyRepeatInterval">@integer/config_key_repeat_interval</item> + <item name="longPressKeyTimeout">@integer/config_long_press_key_timeout</item> + <item name="longPressShiftKeyTimeout">@integer/config_long_press_shift_key_timeout</item> + <item name="longPressSpaceKeyTimeout">@integer/config_long_press_space_key_timeout</item> + <item name="ignoreSpecialKeyTimeout">@integer/config_ignore_special_key_timeout</item> + <item name="showMoreKeysKeyboardAtTouchedPoint">@bool/config_show_more_keys_keyboard_at_touched_point</item> </style> <style - name="MiniKeyboard" + name="LatinKeyboardView" + parent="KeyboardView"> + <item name="autoCorrectionSpacebarLedEnabled">true</item> + <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item> + <item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item> + <item name="spacebarTextColor">#FFC0C0C0</item> + <item name="spacebarTextShadowColor">#80000000</item> + </style> + <style + name="MoreKeysKeyboard" parent="Keyboard" > <item name="keyboardTopPadding">0dip</item> @@ -80,16 +96,16 @@ <item name="horizontalGap">0dip</item> </style> <style - name="MiniKeyboardView" + name="MoreKeysKeyboardView" parent="KeyboardView" > <item name="keyBackground">@drawable/btn_keyboard_key_popup</item> - <item name="verticalCorrection">@dimen/mini_keyboard_vertical_correction</item> + <item name="verticalCorrection">@dimen/more_keys_keyboard_vertical_correction</item> </style> - <style name="MiniKeyboardPanelStyle"> + <style name="MoreKeysKeyboardPanelStyle"> <item name="android:background">@drawable/keyboard_popup_panel_background</item> - <item name="android:paddingLeft">@dimen/mini_keyboard_horizontal_edges_padding</item> - <item name="android:paddingRight">@dimen/mini_keyboard_horizontal_edges_padding</item> + <item name="android:paddingLeft">@dimen/more_keys_keyboard_horizontal_edges_padding</item> + <item name="android:paddingRight">@dimen/more_keys_keyboard_horizontal_edges_padding</item> </style> <style name="SuggestionsStripBackgroundStyle"> <item name="android:background">@drawable/keyboard_suggest_strip</item> @@ -98,7 +114,8 @@ name="SuggestionsViewStyle" parent="SuggestionsStripBackgroundStyle" > - <item name="suggestionStripOption">autoCorrectBold</item> + <item name="suggestionStripOption">autoCorrectBold|validTypedWordBold</item> + <item name="colorValidTypedWord">#FFFCAE00</item> <item name="colorTypedWord">@android:color/white</item> <item name="colorAutoCorrect">#FFFCAE00</item> <item name="colorSuggested">#FFFCAE00</item> @@ -110,7 +127,7 @@ </style> <style name="MoreSuggestionsViewStyle" - parent="MiniKeyboardView" + parent="MoreKeysKeyboardView" > </style> <style name="SuggestionBackgroundStyle"> @@ -133,6 +150,16 @@ <item name="android:background">@android:color/black</item> <item name="keyBackground">@drawable/btn_keyboard_key3</item> </style> + <style + name="LatinKeyboardView.HighContrast" + parent="KeyboardView.HighContrast" + > + <item name="autoCorrectionSpacebarLedEnabled">true</item> + <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item> + <item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item> + <item name="spacebarTextColor">#FFC0C0C0</item> + <item name="spacebarTextShadowColor">#80000000</item> + </style> <!-- Theme "Stone" --> <style name="Keyboard.Stone" @@ -146,13 +173,6 @@ <item name="verticalGap">@fraction/key_bottom_gap_stone</item> </style> <style - name="LatinKeyboard.Stone" - parent="LatinKeyboard" - > - <item name="spacebarTextColor">#FF000000</item> - <item name="spacebarTextShadowColor">#D0FFFFFF</item> - </style> - <style name="KeyboardView.Stone" parent="KeyboardView" > @@ -161,12 +181,22 @@ <item name="keyTextInactivatedColor">#FF808080</item> <item name="keyHintLetterColor">#80000000</item> <item name="keyHintLabelColor">#E0000000</item> - <item name="keyUppercaseLetterInactivatedColor">#66000000</item> - <item name="keyUppercaseLetterActivatedColor">#CC000000</item> + <item name="keyShiftedLetterHintInactivatedColor">#66000000</item> + <item name="keyShiftedLetterHintActivatedColor">#CC000000</item> <item name="shadowColor">#FFFFFFFF</item> </style> <style - name="MiniKeyboard.Stone" + name="LatinKeyboardView.Stone" + parent="KeyboardView.Stone" + > + <item name="autoCorrectionSpacebarLedEnabled">true</item> + <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item> + <item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item> + <item name="spacebarTextColor">#FF000000</item> + <item name="spacebarTextShadowColor">#D0FFFFFF</item> + </style> + <style + name="MoreKeysKeyboard.Stone" parent="Keyboard.Stone" > <item name="keyboardTopPadding">0dip</item> @@ -174,8 +204,8 @@ <item name="horizontalGap">0dip</item> </style> <style - name="MiniKeyboardView.Stone" - parent="MiniKeyboardView" + name="MoreKeysKeyboardView.Stone" + parent="MoreKeysKeyboardView" > <item name="keyBackground">@drawable/btn_keyboard_key_stone</item> <item name="keyTextColor">#FF000000</item> @@ -194,6 +224,16 @@ > <item name="keyTextStyle">bold</item> </style> + <style + name="LatinKeyboardView.Stone.Bold" + parent="KeyboardView.Stone.Bold" + > + <item name="autoCorrectionSpacebarLedEnabled">true</item> + <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item> + <item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item> + <item name="spacebarTextColor">#FF000000</item> + <item name="spacebarTextShadowColor">#D0FFFFFF</item> + </style> <!-- Theme "Gingerbread" --> <style name="Keyboard.Gingerbread" @@ -213,7 +253,17 @@ <item name="keyTextStyle">bold</item> </style> <style - name="MiniKeyboard.Gingerbread" + name="LatinKeyboardView.Gingerbread" + parent="KeyboardView.Gingerbread" + > + <item name="autoCorrectionSpacebarLedEnabled">true</item> + <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led</item> + <item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item> + <item name="spacebarTextColor">#FFC0C0C0</item> + <item name="spacebarTextShadowColor">#80000000</item> + </style> + <style + name="MoreKeysKeyboard.Gingerbread" parent="Keyboard.Gingerbread" > <item name="keyboardTopPadding">0dip</item> @@ -221,8 +271,8 @@ <item name="horizontalGap">0dip</item> </style> <style - name="MiniKeyboardView.Gingerbread" - parent="MiniKeyboardView" + name="MoreKeysKeyboardView.Gingerbread" + parent="MoreKeysKeyboardView" > <item name="android:background">@null</item> </style> @@ -239,12 +289,6 @@ <item name="touchPositionCorrectionData">@array/touch_position_correction_data_ice_cream_sandwich</item> </style> <style - name="LatinKeyboard.IceCreamSandwich" - parent="LatinKeyboard" - > - <item name="disabledShortcutIcon">@drawable/sym_keyboard_voice_off_holo</item> - </style> - <style name="KeyboardView.IceCreamSandwich" parent="KeyboardView" > @@ -254,8 +298,8 @@ <item name="keyTextInactivatedColor">#66E0E4E5</item> <item name="keyHintLetterColor">#80000000</item> <item name="keyHintLabelColor">#A0FFFFFF</item> - <item name="keyUppercaseLetterInactivatedColor">#66E0E4E5</item> - <item name="keyUppercaseLetterActivatedColor">#FFFFFFFF</item> + <item name="keyShiftedLetterHintInactivatedColor">#66E0E4E5</item> + <item name="keyShiftedLetterHintActivatedColor">#FFFFFFFF</item> <item name="keyPreviewBackground">@drawable/keyboard_key_feedback_ics</item> <item name="keyPreviewLeftBackground">@drawable/keyboard_key_feedback_left_ics</item> <item name="keyPreviewRightBackground">@drawable/keyboard_key_feedback_right_ics</item> @@ -268,7 +312,17 @@ <item name="shadowRadius">0.0</item> </style> <style - name="MiniKeyboard.IceCreamSandwich" + name="LatinKeyboardView.IceCreamSandwich" + parent="KeyboardView.IceCreamSandwich" + > + <item name="autoCorrectionSpacebarLedEnabled">false</item> + <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led_holo</item> + <item name="spacebarTextRatio">@fraction/spacebar_text_ratio</item> + <item name="spacebarTextColor">#FFC0C0C0</item> + <item name="spacebarTextShadowColor">#80000000</item> + </style> + <style + name="MoreKeysKeyboard.IceCreamSandwich" parent="Keyboard.IceCreamSandwich" > <item name="keyboardTopPadding">0dip</item> @@ -276,16 +330,16 @@ <item name="horizontalGap">0dip</item> </style> <style - name="MiniKeyboardView.IceCreamSandwich" - parent="MiniKeyboardView" + name="MoreKeysKeyboardView.IceCreamSandwich" + parent="MoreKeysKeyboardView" > <item name="android:background">@null</item> <item name="keyBackground">@drawable/btn_keyboard_key_popup_ics</item> </style> - <style name="MiniKeyboardPanelStyle.IceCreamSandwich"> + <style name="MoreKeysKeyboardPanelStyle.IceCreamSandwich"> <item name="android:background">@drawable/keyboard_popup_panel_background_holo</item> - <item name="android:paddingLeft">@dimen/mini_keyboard_horizontal_edges_padding_ics</item> - <item name="android:paddingRight">@dimen/mini_keyboard_horizontal_edges_padding_ics</item> + <item name="android:paddingLeft">@dimen/more_keys_keyboard_horizontal_edges_padding_ics</item> + <item name="android:paddingRight">@dimen/more_keys_keyboard_horizontal_edges_padding_ics</item> </style> <style name="SuggestionsStripBackgroundStyle.IceCreamSandwich"> <item name="android:background">@drawable/keyboard_suggest_strip_holo</item> @@ -296,11 +350,12 @@ > <item name="suggestionStripOption">autoCorrectBold|validTypedWordBold</item> <!-- android:color/holo_blue_light=#FF33B5E5 --> + <item name="colorValidTypedWord">@android:color/holo_blue_light</item> <item name="colorTypedWord">@android:color/holo_blue_light</item> <item name="colorAutoCorrect">@android:color/holo_blue_light</item> <item name="colorSuggested">@android:color/holo_blue_light</item> + <item name="alphaValidTypedWord">85</item> <item name="alphaTypedWord">85</item> - <item name="alphaAutoCorrect">100</item> <item name="alphaSuggested">70</item> <item name="alphaObsoleted">70</item> <item name="suggestionsCountInStrip">@integer/suggestions_count_in_strip</item> @@ -310,7 +365,7 @@ </style> <style name="MoreSuggestionsViewStyle.IceCreamSandwich" - parent="MiniKeyboardView.IceCreamSandwich" + parent="MoreKeysKeyboardView.IceCreamSandwich" > </style> <style name="SuggestionBackgroundStyle.IceCreamSandwich"> @@ -318,11 +373,11 @@ </style> <style name="SuggestionPreviewBackgroundStyle.IceCreamSandwich" - parent="MiniKeyboardPanelStyle.IceCreamSandwich" + parent="MoreKeysKeyboardPanelStyle.IceCreamSandwich" > </style> - <style name="MiniKeyboardAnimation"> - <item name="android:windowEnterAnimation">@anim/mini_keyboard_fadein</item> - <item name="android:windowExitAnimation">@anim/mini_keyboard_fadeout</item> + <style name="MoreKeysKeyboardAnimation"> + <item name="android:windowEnterAnimation">@anim/more_keys_keyboard_fadein</item> + <item name="android:windowExitAnimation">@anim/more_keys_keyboard_fadeout</item> </style> </resources> diff --git a/java/res/values/themes-basic-highcontrast.xml b/java/res/values/themes-basic-highcontrast.xml index abb7c8057..19df42ce1 100644 --- a/java/res/values/themes-basic-highcontrast.xml +++ b/java/res/values/themes-basic-highcontrast.xml @@ -17,11 +17,11 @@ <resources> <style name="KeyboardTheme.HighContrast" parent="KeyboardIcons"> <item name="keyboardStyle">@style/Keyboard.HighContrast</item> - <item name="latinKeyboardStyle">@style/LatinKeyboard</item> <item name="keyboardViewStyle">@style/KeyboardView.HighContrast</item> - <item name="miniKeyboardStyle">@style/MiniKeyboard</item> - <item name="miniKeyboardViewStyle">@style/MiniKeyboardView</item> - <item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item> + <item name="latinKeyboardViewStyle">@style/LatinKeyboardView.HighContrast</item> + <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard</item> + <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView</item> + <item name="moreKeysKeyboardPanelStyle">@style/MoreKeysKeyboardPanelStyle</item> <item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item> <item name="suggestionsViewStyle">@style/SuggestionsViewStyle</item> <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item> diff --git a/java/res/values/themes-basic.xml b/java/res/values/themes-basic.xml index ff9fed55f..5d477206d 100644 --- a/java/res/values/themes-basic.xml +++ b/java/res/values/themes-basic.xml @@ -17,11 +17,11 @@ <resources> <style name="KeyboardTheme" parent="KeyboardIcons"> <item name="keyboardStyle">@style/Keyboard</item> - <item name="latinKeyboardStyle">@style/LatinKeyboard</item> <item name="keyboardViewStyle">@style/KeyboardView</item> - <item name="miniKeyboardStyle">@style/MiniKeyboard</item> - <item name="miniKeyboardViewStyle">@style/MiniKeyboardView</item> - <item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item> + <item name="latinKeyboardViewStyle">@style/LatinKeyboardView</item> + <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard</item> + <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView</item> + <item name="moreKeysKeyboardPanelStyle">@style/MoreKeysKeyboardPanelStyle</item> <item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item> <item name="suggestionsViewStyle">@style/SuggestionsViewStyle</item> <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item> diff --git a/java/res/values/themes-gingerbread.xml b/java/res/values/themes-gingerbread.xml index be853eb0f..a13979818 100644 --- a/java/res/values/themes-gingerbread.xml +++ b/java/res/values/themes-gingerbread.xml @@ -17,11 +17,11 @@ <resources> <style name="KeyboardTheme.Gingerbread" parent="KeyboardIcons"> <item name="keyboardStyle">@style/Keyboard.Gingerbread</item> - <item name="latinKeyboardStyle">@style/LatinKeyboard</item> <item name="keyboardViewStyle">@style/KeyboardView.Gingerbread</item> - <item name="miniKeyboardStyle">@style/MiniKeyboard.Gingerbread</item> - <item name="miniKeyboardViewStyle">@style/MiniKeyboardView.Gingerbread</item> - <item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item> + <item name="latinKeyboardViewStyle">@style/LatinKeyboardView.Gingerbread</item> + <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.Gingerbread</item> + <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.Gingerbread</item> + <item name="moreKeysKeyboardPanelStyle">@style/MoreKeysKeyboardPanelStyle</item> <item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item> <item name="suggestionsViewStyle">@style/SuggestionsViewStyle</item> <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item> diff --git a/java/res/values/themes-ics.xml b/java/res/values/themes-ics.xml index 618aaed79..e6fd4f451 100644 --- a/java/res/values/themes-ics.xml +++ b/java/res/values/themes-ics.xml @@ -17,11 +17,11 @@ <resources> <style name="KeyboardTheme.IceCreamSandwich" parent="KeyboardIcons.IceCreamSandwich"> <item name="keyboardStyle">@style/Keyboard.IceCreamSandwich</item> - <item name="latinKeyboardStyle">@style/LatinKeyboard.IceCreamSandwich</item> <item name="keyboardViewStyle">@style/KeyboardView.IceCreamSandwich</item> - <item name="miniKeyboardStyle">@style/MiniKeyboard.IceCreamSandwich</item> - <item name="miniKeyboardViewStyle">@style/MiniKeyboardView.IceCreamSandwich</item> - <item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle.IceCreamSandwich</item> + <item name="latinKeyboardViewStyle">@style/LatinKeyboardView.IceCreamSandwich</item> + <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.IceCreamSandwich</item> + <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.IceCreamSandwich</item> + <item name="moreKeysKeyboardPanelStyle">@style/MoreKeysKeyboardPanelStyle.IceCreamSandwich</item> <item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle.IceCreamSandwich</item> <item name="suggestionsViewStyle">@style/SuggestionsViewStyle.IceCreamSandwich</item> <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle.IceCreamSandwich</item> diff --git a/java/res/values/themes-stone-bold.xml b/java/res/values/themes-stone-bold.xml index 532a2985e..47de99e47 100644 --- a/java/res/values/themes-stone-bold.xml +++ b/java/res/values/themes-stone-bold.xml @@ -17,11 +17,11 @@ <resources> <style name="KeyboardTheme.Stone.Bold" parent="KeyboardIcons.Black"> <item name="keyboardStyle">@style/Keyboard.Stone.Bold</item> - <item name="latinKeyboardStyle">@style/LatinKeyboard.Stone</item> <item name="keyboardViewStyle">@style/KeyboardView.Stone.Bold</item> - <item name="miniKeyboardStyle">@style/MiniKeyboard.Stone</item> - <item name="miniKeyboardViewStyle">@style/MiniKeyboardView.Stone</item> - <item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item> + <item name="latinKeyboardViewStyle">@style/LatinKeyboardView.Stone.Bold</item> + <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.Stone</item> + <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.Stone</item> + <item name="moreKeysKeyboardPanelStyle">@style/MoreKeysKeyboardPanelStyle</item> <item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item> <item name="suggestionsViewStyle">@style/SuggestionsViewStyle</item> <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item> diff --git a/java/res/values/themes-stone.xml b/java/res/values/themes-stone.xml index cb3edc58f..a0b39e3e6 100644 --- a/java/res/values/themes-stone.xml +++ b/java/res/values/themes-stone.xml @@ -17,11 +17,11 @@ <resources> <style name="KeyboardTheme.Stone" parent="KeyboardIcons.Black"> <item name="keyboardStyle">@style/Keyboard.Stone</item> - <item name="latinKeyboardStyle">@style/LatinKeyboard.Stone</item> <item name="keyboardViewStyle">@style/KeyboardView.Stone</item> - <item name="miniKeyboardStyle">@style/MiniKeyboard.Stone</item> - <item name="miniKeyboardViewStyle">@style/MiniKeyboardView.Stone</item> - <item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item> + <item name="latinKeyboardViewStyle">@style/LatinKeyboardView.Stone</item> + <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.Stone</item> + <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.Stone</item> + <item name="moreKeysKeyboardPanelStyle">@style/MoreKeysKeyboardPanelStyle</item> <item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item> <item name="suggestionsViewStyle">@style/SuggestionsViewStyle</item> <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item> diff --git a/java/res/xml-ar/keyboard_set.xml b/java/res/xml-ar/keyboard_set.xml new file mode 100644 index 000000000..7b70f633c --- /dev/null +++ b/java/res/xml-ar/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="ar" > + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_arabic" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-be/keyboard_set.xml b/java/res/xml-be/keyboard_set.xml new file mode 100644 index 000000000..042264aae --- /dev/null +++ b/java/res/xml-be/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="be"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_slavic" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-bg/keyboard_set.xml b/java/res/xml-bg/keyboard_set.xml new file mode 100644 index 000000000..49914d54b --- /dev/null +++ b/java/res/xml-bg/keyboard_set.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="bg"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_bulgarian" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-cs/keyboard_set.xml b/java/res/xml-cs/keyboard_set.xml new file mode 100644 index 000000000..b4535164b --- /dev/null +++ b/java/res/xml-cs/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="cs"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_qwertz" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-da/keyboard_set.xml b/java/res/xml-da/keyboard_set.xml new file mode 100644 index 000000000..cf01ae6f5 --- /dev/null +++ b/java/res/xml-da/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="da"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_scandinavian" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-de-rZZ/keyboard_set.xml b/java/res/xml-de-rZZ/keyboard_set.xml new file mode 100644 index 000000000..635884d1d --- /dev/null +++ b/java/res/xml-de-rZZ/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="de"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_qwerty" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-de/kbd_qwerty.xml b/java/res/xml-de/kbd_qwerty.xml deleted file mode 100644 index 89e10b26d..000000000 --- a/java/res/xml-de/kbd_qwerty.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2008, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ ---> - -<Keyboard - xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyboardLocale="de" -> - <include - latin:keyboardLayout="@xml/kbd_rows_qwertz" /> -</Keyboard> diff --git a/java/res/xml-de/keyboard_set.xml b/java/res/xml-de/keyboard_set.xml new file mode 100644 index 000000000..485e63f06 --- /dev/null +++ b/java/res/xml-de/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="de"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_qwertz" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-es/kbd_qwerty.xml b/java/res/xml-es/kbd_qwerty.xml deleted file mode 100644 index 568f4d652..000000000 --- a/java/res/xml-es/kbd_qwerty.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?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:keyboardLocale="es,es_US" -> - <include - latin:keyboardLayout="@xml/kbd_rows_spanish" /> -</Keyboard> diff --git a/java/res/xml-es/keyboard_set.xml b/java/res/xml-es/keyboard_set.xml new file mode 100644 index 000000000..2944a83ad --- /dev/null +++ b/java/res/xml-es/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="es,es_US"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_spanish" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-et/keyboard_set.xml b/java/res/xml-et/keyboard_set.xml new file mode 100644 index 000000000..1c23db3d8 --- /dev/null +++ b/java/res/xml-et/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="et"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_scandinavian" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-fi/kbd_qwerty.xml b/java/res/xml-fi/kbd_qwerty.xml deleted file mode 100644 index 75721e057..000000000 --- a/java/res/xml-fi/kbd_qwerty.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?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:keyboardLocale="fi" -> - <include - latin:keyboardLayout="@xml/kbd_rows_scandinavian" /> -</Keyboard> diff --git a/java/res/xml-fi/keyboard_set.xml b/java/res/xml-fi/keyboard_set.xml new file mode 100644 index 000000000..e8e4e7d9a --- /dev/null +++ b/java/res/xml-fi/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="fi"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_scandinavian" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-fr-rCA/kbd_qwerty.xml b/java/res/xml-fr-rCA/kbd_qwerty.xml deleted file mode 100644 index 7bdfbadf1..000000000 --- a/java/res/xml-fr-rCA/kbd_qwerty.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2008, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ ---> - -<Keyboard - xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyboardLocale="fr_CA" -> - <include - latin:keyboardLayout="@xml/kbd_rows_qwerty" /> -</Keyboard> diff --git a/java/res/xml-fr-rCA/keyboard_set.xml b/java/res/xml-fr-rCA/keyboard_set.xml new file mode 100644 index 000000000..ea6ac8f26 --- /dev/null +++ b/java/res/xml-fr-rCA/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="fr_CA"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_qwerty" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-fr-rCH/kbd_qwerty.xml b/java/res/xml-fr-rCH/kbd_qwerty.xml deleted file mode 100644 index 41b701d83..000000000 --- a/java/res/xml-fr-rCH/kbd_qwerty.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2008, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ ---> - -<Keyboard - xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyboardLocale="fr_CH" -> - <include - latin:keyboardLayout="@xml/kbd_rows_qwertz" /> -</Keyboard> diff --git a/java/res/xml-fr-rCH/keyboard_set.xml b/java/res/xml-fr-rCH/keyboard_set.xml new file mode 100644 index 000000000..751900b88 --- /dev/null +++ b/java/res/xml-fr-rCH/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="fr_CH"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_qwertz" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-fr/keyboard_set.xml b/java/res/xml-fr/keyboard_set.xml new file mode 100644 index 000000000..42a20e5ea --- /dev/null +++ b/java/res/xml-fr/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="fr"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_azerty" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-hr/kbd_qwerty.xml b/java/res/xml-hr/kbd_qwerty.xml deleted file mode 100644 index ca92e86a7..000000000 --- a/java/res/xml-hr/kbd_qwerty.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?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:keyboardLocale="hr" -> - <!-- TODO: Dedicated Croatian layout especially for tablet. --> - <include - latin:keyboardLayout="@xml/kbd_rows_qwertz" /> -</Keyboard> diff --git a/java/res/xml-hr/keyboard_set.xml b/java/res/xml-hr/keyboard_set.xml new file mode 100644 index 000000000..e17aefdf6 --- /dev/null +++ b/java/res/xml-hr/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="hr"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_qwertz" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-hu/keyboard_set.xml b/java/res/xml-hu/keyboard_set.xml new file mode 100644 index 000000000..0f6e5759e --- /dev/null +++ b/java/res/xml-hu/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="hu"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_qwertz" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-iw/kbd_qwerty.xml b/java/res/xml-iw/kbd_qwerty.xml deleted file mode 100644 index 54cd4b5e9..000000000 --- a/java/res/xml-iw/kbd_qwerty.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2010, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ ---> - -<Keyboard - xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyboardLocale="iw" - latin:isRtlKeyboard="true" -> - <include - latin:keyboardLayout="@xml/kbd_rows_hebrew" /> -</Keyboard> diff --git a/java/res/xml-iw/kbd_symbols.xml b/java/res/xml-iw/kbd_symbols.xml deleted file mode 100644 index 9e5c255d0..000000000 --- a/java/res/xml-iw/kbd_symbols.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?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:isRtlKeyboard="true" -> - <include - latin:keyboardLayout="@xml/kbd_rows_symbols" /> -</Keyboard> diff --git a/java/res/xml-iw/kbd_symbols_shift.xml b/java/res/xml-iw/kbd_symbols_shift.xml deleted file mode 100644 index 934e6f849..000000000 --- a/java/res/xml-iw/kbd_symbols_shift.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?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:isRtlKeyboard="true" -> - <include - latin:keyboardLayout="@xml/kbd_rows_symbols_shift" /> -</Keyboard> diff --git a/java/res/xml-iw/keyboard_set.xml b/java/res/xml-iw/keyboard_set.xml new file mode 100644 index 000000000..501ba96ee --- /dev/null +++ b/java/res/xml-iw/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="iw"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_hebrew" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-ky/keyboard_set.xml b/java/res/xml-ky/keyboard_set.xml new file mode 100644 index 000000000..abd5f1631 --- /dev/null +++ b/java/res/xml-ky/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="ky"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_slavic" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-land/kbd_number.xml b/java/res/xml-land/kbd_number.xml index f5930ef41..7cc0fb274 100644 --- a/java/res/xml-land/kbd_number.xml +++ b/java/res/xml-land/kbd_number.xml @@ -24,5 +24,5 @@ latin:keyWidth="26.67%p" > <include - latin:keyboardLayout="@xml/kbd_rows_number" /> + latin:keyboardLayout="@xml/rows_number" /> </Keyboard> diff --git a/java/res/xml-land/kbd_phone.xml b/java/res/xml-land/kbd_phone.xml index 3b1fb36ff..aa54b8390 100644 --- a/java/res/xml-land/kbd_phone.xml +++ b/java/res/xml-land/kbd_phone.xml @@ -24,5 +24,5 @@ latin:keyWidth="26.67%p" > <include - latin:keyboardLayout="@xml/kbd_rows_phone" /> + latin:keyboardLayout="@xml/rows_phone" /> </Keyboard> diff --git a/java/res/xml-land/kbd_phone_shift.xml b/java/res/xml-land/kbd_phone_symbols.xml index e59664776..41ba6cf3b 100644 --- a/java/res/xml-land/kbd_phone_shift.xml +++ b/java/res/xml-land/kbd_phone_symbols.xml @@ -24,5 +24,5 @@ latin:keyWidth="26.67%p" > <include - latin:keyboardLayout="@xml/kbd_rows_phone_shift" /> + latin:keyboardLayout="@xml/rows_phone_symbols" /> </Keyboard> diff --git a/java/res/xml-nb/kbd_qwerty.xml b/java/res/xml-nb/kbd_qwerty.xml deleted file mode 100644 index 1f4e86e89..000000000 --- a/java/res/xml-nb/kbd_qwerty.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2010, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ ---> - -<Keyboard - xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyboardLocale="nb" -> - <include - latin:keyboardLayout="@xml/kbd_rows_scandinavian" /> -</Keyboard> diff --git a/java/res/xml-nb/keyboard_set.xml b/java/res/xml-nb/keyboard_set.xml new file mode 100644 index 000000000..d146beb71 --- /dev/null +++ b/java/res/xml-nb/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="nb"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_scandinavian" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-pl/keyboard_set.xml b/java/res/xml-pl/keyboard_set.xml new file mode 100644 index 000000000..6d2737929 --- /dev/null +++ b/java/res/xml-pl/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="pl"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_qwerty" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-pt/kbd_qwerty.xml b/java/res/xml-pt/kbd_qwerty.xml deleted file mode 100644 index f5dcbc61b..000000000 --- a/java/res/xml-pt/kbd_qwerty.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?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:keyboardLocale="pt" -> - <include - latin:keyboardLayout="@xml/kbd_rows_qwerty" /> -</Keyboard> diff --git a/java/res/xml-pt/keyboard_set.xml b/java/res/xml-pt/keyboard_set.xml new file mode 100644 index 000000000..65f9634ce --- /dev/null +++ b/java/res/xml-pt/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="pt"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_qwerty" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-ro/keyboard_set.xml b/java/res/xml-ro/keyboard_set.xml new file mode 100644 index 000000000..6c34966d0 --- /dev/null +++ b/java/res/xml-ro/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="ro"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_qwerty" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-ru/kbd_qwerty.xml b/java/res/xml-ru/kbd_qwerty.xml deleted file mode 100644 index aee1b1bfc..000000000 --- a/java/res/xml-ru/kbd_qwerty.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2008, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ ---> - -<Keyboard - xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyboardLocale="ru" -> - <include - latin:keyboardLayout="@xml/kbd_rows_russian" /> -</Keyboard> diff --git a/java/res/xml-ru/keyboard_set.xml b/java/res/xml-ru/keyboard_set.xml new file mode 100644 index 000000000..b6a356891 --- /dev/null +++ b/java/res/xml-ru/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="ru"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_slavic" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-sk/keyboard_set.xml b/java/res/xml-sk/keyboard_set.xml new file mode 100644 index 000000000..b283d968a --- /dev/null +++ b/java/res/xml-sk/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="sk"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_qwerty" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-sl/keyboard_set.xml b/java/res/xml-sl/keyboard_set.xml new file mode 100644 index 000000000..dbb2782f0 --- /dev/null +++ b/java/res/xml-sl/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="sl"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_qwerty" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-sr/kbd_qwerty.xml b/java/res/xml-sr/kbd_qwerty.xml deleted file mode 100644 index 58fc187c2..000000000 --- a/java/res/xml-sr/kbd_qwerty.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2008, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ ---> - -<Keyboard - xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyboardLocale="sr" -> - <include - latin:keyboardLayout="@xml/kbd_rows_serbian" /> -</Keyboard> diff --git a/java/res/xml-sr/keyboard_set.xml b/java/res/xml-sr/keyboard_set.xml new file mode 100644 index 000000000..15471dbcd --- /dev/null +++ b/java/res/xml-sr/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="sr"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_serbian" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-sv/kbd_qwerty.xml b/java/res/xml-sv/kbd_qwerty.xml deleted file mode 100644 index e29d9abce..000000000 --- a/java/res/xml-sv/kbd_qwerty.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2008, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ ---> - -<Keyboard - xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyboardLocale="sv" -> - <include - latin:keyboardLayout="@xml/kbd_rows_scandinavian" /> -</Keyboard> diff --git a/java/res/xml-sv/keyboard_set.xml b/java/res/xml-sv/keyboard_set.xml new file mode 100644 index 000000000..e5184d33f --- /dev/null +++ b/java/res/xml-sv/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="sv"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_scandinavian" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-sw600dp-land/kbd_mini_keyboard_template.xml b/java/res/xml-sw600dp-land/kbd_more_keys_keyboard_template.xml index 8272e02f0..4d8b446a2 100644 --- a/java/res/xml-sw600dp-land/kbd_mini_keyboard_template.xml +++ b/java/res/xml-sw600dp-land/kbd_more_keys_keyboard_template.xml @@ -21,6 +21,6 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" latin:keyWidth="5%p" latin:rowHeight="@dimen/popup_key_height" - style="?attr/miniKeyboardStyle" + style="?attr/moreKeysKeyboardStyle" > </Keyboard> diff --git a/java/res/xml-ar/kbd_symbols.xml b/java/res/xml-sw600dp-land/kbd_number.xml index 9e5c255d0..9d358b678 100644 --- a/java/res/xml-ar/kbd_symbols.xml +++ b/java/res/xml-sw600dp-land/kbd_number.xml @@ -20,8 +20,9 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:isRtlKeyboard="true" + latin:keyboardHorizontalEdgesPadding="10%p" + latin:keyWidth="15.00%p" > <include - latin:keyboardLayout="@xml/kbd_rows_symbols" /> + latin:keyboardLayout="@xml/rows_number" /> </Keyboard> diff --git a/java/res/xml-ar/kbd_qwerty.xml b/java/res/xml-sw600dp-land/kbd_phone.xml index b26a938cc..abac6bd4f 100644 --- a/java/res/xml-ar/kbd_qwerty.xml +++ b/java/res/xml-sw600dp-land/kbd_phone.xml @@ -20,9 +20,9 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyboardLocale="ar" - latin:isRtlKeyboard="true" + latin:keyboardHorizontalEdgesPadding="10%p" + latin:keyWidth="15.00%p" > <include - latin:keyboardLayout="@xml/kbd_rows_arabic" /> + latin:keyboardLayout="@xml/rows_phone" /> </Keyboard> diff --git a/java/res/xml-sw600dp-land/kbd_phone_symbols.xml b/java/res/xml-sw600dp-land/kbd_phone_symbols.xml new file mode 100644 index 000000000..e3f56bce7 --- /dev/null +++ b/java/res/xml-sw600dp-land/kbd_phone_symbols.xml @@ -0,0 +1,29 @@ +<?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" +> + <!-- Tablet doesn't have phone symbols keyboard --> + <include + latin:keyboardLayout="@xml/rows_phone" /> +</Keyboard> diff --git a/java/res/xml-sw600dp/kbd_mini_keyboard_template.xml b/java/res/xml-sw600dp/kbd_more_keys_keyboard_template.xml index 0d5795f6a..d90a5884e 100644 --- a/java/res/xml-sw600dp/kbd_mini_keyboard_template.xml +++ b/java/res/xml-sw600dp/kbd_more_keys_keyboard_template.xml @@ -21,6 +21,6 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" latin:keyWidth="8%p" latin:rowHeight="@dimen/popup_key_height" - style="?attr/miniKeyboardStyle" + style="?attr/moreKeysKeyboardStyle" > </Keyboard> diff --git a/java/res/xml-sw600dp/kbd_number.xml b/java/res/xml-sw600dp/kbd_number.xml index 46114dedf..70cf6a2ca 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/rows_number" /> </Keyboard> diff --git a/java/res/xml-sw600dp/kbd_phone.xml b/java/res/xml-sw600dp/kbd_phone.xml index 303f8145b..72acef21c 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/rows_phone" /> </Keyboard> diff --git a/java/res/xml-sw600dp/kbd_phone_symbols.xml b/java/res/xml-sw600dp/kbd_phone_symbols.xml new file mode 100644 index 000000000..9faeaf4e0 --- /dev/null +++ b/java/res/xml-sw600dp/kbd_phone_symbols.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:keyWidth="15.00%p" +> + <!-- Tablet doesn't have phone symbols keyboard --> + <include + latin:keyboardLayout="@xml/rows_phone" /> +</Keyboard> diff --git a/java/res/xml-sw600dp/kbd_qwerty_f2.xml b/java/res/xml-sw600dp/key_f2.xml index b25afc12f..b25afc12f 100644 --- a/java/res/xml-sw600dp/kbd_qwerty_f2.xml +++ b/java/res/xml-sw600dp/key_f2.xml diff --git a/java/res/xml-sw600dp/kbd_row3_smiley.xml b/java/res/xml-sw600dp/key_smiley.xml index f9b647cdf..3430d7898 100644 --- a/java/res/xml-sw600dp/kbd_row3_smiley.xml +++ b/java/res/xml-sw600dp/key_smiley.xml @@ -26,37 +26,29 @@ latin:mode="email" > <Key - latin:keyLabel="\@" - latin:keyXPos="-8.9%p" - latin:keyWidth="fillBoth" /> + latin:keyLabel="\@" /> </case> <case latin:mode="url" > <Key latin:keyLabel="-" - latin:keyLabelOption="hasUppercaseLetter" latin:keyHintLabel="_" latin:moreKeys="_" - latin:keyXPos="-8.9%p" - latin:keyWidth="fillBoth" /> + latin:keyStyle="hasShiftedLetterHintStyle" /> </case> <case latin:imeAction="actionSearch" > <Key latin:keyLabel=":" - latin:keyLabelOption="hasUppercaseLetter" latin:keyHintLabel="+" latin:moreKeys="+" - latin:keyXPos="-8.9%p" - latin:keyWidth="fillBoth" /> + latin:keyStyle="hasShiftedLetterHintStyle" /> </case> <default> <Key - latin:keyStyle="smileyKeyStyle" - latin:keyXPos="-8.9%p" - latin:keyWidth="fillBoth" /> + latin:keyStyle="smileyKeyStyle" /> </default> </switch> </merge> diff --git a/java/res/xml-sw600dp/kbd_key_styles.xml b/java/res/xml-sw600dp/key_styles_common.xml index 25fa8b265..e524aa381 100644 --- a/java/res/xml-sw600dp/kbd_key_styles.xml +++ b/java/res/xml-sw600dp/key_styles_common.xml @@ -33,51 +33,92 @@ <default> <key-style latin:styleName="f2PopupStyle" - latin:keyLabelOption="hasPopupHint" - latin:moreKeys="\@icon/3|\@integer/key_settings" + latin:keyLabelFlags="hasPopupHint" + latin:moreKeys="\@icon/settingsKey|\@integer/key_settings" latin:backgroundType="functional" /> </default> </switch> + <switch> + <case + latin:keyboardSetElement="alphabetManualShifted|alphabetShiftLockShifted" + > + <key-style + latin:styleName="hasShiftedLetterHintStyle" + latin:keyLabelFlags="hasShiftedLetterHint|shiftedLetterActivated" /> + </case> + <default> + <key-style + latin:styleName="hasShiftedLetterHintStyle" + latin:keyLabelFlags="hasShiftedLetterHint" /> + </default> + </switch> <!-- Functional key styles --> - <key-style - latin:styleName="shiftKeyStyle" - latin:code="@integer/key_shift" - latin:keyIcon="iconShiftKey" - latin:keyIconShifted="iconShiftedShiftKey" - latin:backgroundType="sticky" /> + <switch> + <case + latin:keyboardSetElement="alphabetManualShifted|alphabetAutomaticShifted" + > + <key-style + latin:styleName="shiftKeyStyle" + latin:code="@integer/key_shift" + latin:keyIcon="iconShiftKeyShifted" + latin:keyActionFlags="noKeyPreview" + latin:backgroundType="stickyOff" /> + </case> + <case + latin:keyboardSetElement="alphabetShiftLocked|alphabetShiftLockShifted" + > + <key-style + latin:styleName="shiftKeyStyle" + latin:code="@integer/key_shift" + latin:keyIcon="iconShiftKeyShifted" + latin:keyActionFlags="noKeyPreview" + latin:backgroundType="stickyOn" /> + </case> + <default> + <key-style + latin:styleName="shiftKeyStyle" + latin:code="@integer/key_shift" + latin:keyIcon="iconShiftKey" + latin:keyActionFlags="noKeyPreview" + latin:backgroundType="stickyOff" /> + </default> + </switch> <key-style latin:styleName="deleteKeyStyle" latin:code="@integer/key_delete" latin:keyIcon="iconDeleteKey" - latin:backgroundType="functional" - latin:isRepeatable="true" /> - <key-style - latin:styleName="returnKeyStyle" - latin:code="@integer/key_return" - latin:keyIcon="iconReturnKey" + latin:keyActionFlags="isRepeatable|noKeyPreview" latin:backgroundType="functional" /> + <include + latin:keyboardLayout="@xml/key_styles_enter_tablet" /> <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|preserveCase" latin:moreKeys="@string/more_keys_for_smiley" latin:maxMoreKeysColumn="5" /> <key-style latin:styleName="shortcutKeyStyle" latin:code="@integer/key_shortcut" latin:keyIcon="iconShortcutKey" + latin:keyIconDisabled="iconDisabledShortcutKey" + latin:keyLabelFlags="preserveCase" + latin:keyActionFlags="noKeyPreview|altCodeWhileTyping" latin:parentStyle="f2PopupStyle" /> <key-style latin:styleName="settingsKeyStyle" latin:code="@integer/key_settings" latin:keyIcon="iconSettingsKey" + latin:keyActionFlags="noKeyPreview|altCodeWhileTyping" latin:backgroundType="functional" /> <key-style latin:styleName="tabKeyStyle" @@ -89,26 +130,34 @@ latin:styleName="toSymbolKeyStyle" latin:code="@integer/key_switch_alpha_symbol" latin:keyLabel="@string/label_to_symbol_key" + latin:keyLabelFlags="preserveCase" + 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:keyLabelFlags="preserveCase" + 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:keyLabelFlags="preserveCase" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <key-style latin:styleName="backFromMoreSymbolKeyStyle" latin:code="@integer/key_shift" latin:keyLabel="@string/label_to_symbol_key" + latin:keyLabelFlags="preserveCase" + 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|preserveCase" latin:keyOutputText="@string/keylabel_for_popular_domain" latin:moreKeys="@string/more_keys_for_popular_domain" /> </merge> diff --git a/java/res/xml-sw768dp/kbd_row4_apostrophe_dash.xml b/java/res/xml-sw600dp/keys_apostrophe_dash.xml index 9536e81da..a53c1e4ab 100644 --- a/java/res/xml-sw768dp/kbd_row4_apostrophe_dash.xml +++ b/java/res/xml-sw600dp/keys_apostrophe_dash.xml @@ -33,16 +33,16 @@ > <Key latin:keyLabel="/" - latin:keyLabelOption="hasUppercaseLetter" latin:keyHintLabel=":" - latin:moreKeys=":" /> + latin:moreKeys=":" + latin:keyStyle="hasShiftedLetterHintStyle" /> </case> <default> <Key latin:keyLabel="@string/keylabel_for_apostrophe" - latin:keyLabelOption="hasUppercaseLetter" latin:keyHintLabel="@string/keyhintlabel_for_apostrophe" - latin:moreKeys="@string/more_keys_for_apostrophe" /> + latin:moreKeys="@string/more_keys_for_apostrophe" + latin:keyStyle="hasShiftedLetterHintStyle" /> </default> </switch> <switch> @@ -55,9 +55,9 @@ <default> <Key latin:keyLabel="@string/keylabel_for_dash" - latin:keyLabelOption="hasUppercaseLetter" latin:keyHintLabel="@string/keyhintlabel_for_dash" - latin:moreKeys="@string/more_keys_for_dash" /> + latin:moreKeys="@string/more_keys_for_dash" + latin:keyStyle="hasShiftedLetterHintStyle" /> </default> </switch> </merge> diff --git a/java/res/xml-sw600dp/kbd_qwerty_row1.xml b/java/res/xml-sw600dp/row_qwerty1.xml index 07d8e2296..3d3a1a8ff 100644 --- a/java/res/xml-sw600dp/kbd_qwerty_row1.xml +++ b/java/res/xml-sw600dp/row_qwerty1.xml @@ -25,11 +25,9 @@ latin:keyWidth="9.0%p" > <Key - latin:keyLabel="q" - latin:moreKeys="@string/more_keys_for_q" /> + latin:keyLabel="q" /> <Key - latin:keyLabel="w" - latin:moreKeys="@string/more_keys_for_w" /> + latin:keyLabel="w" /> <Key latin:keyLabel="e" latin:moreKeys="@string/more_keys_for_e" /> @@ -52,8 +50,7 @@ latin:keyLabel="o" latin:moreKeys="@string/more_keys_for_o" /> <Key - latin:keyLabel="p" - latin:moreKeys="@string/more_keys_for_p" /> + latin:keyLabel="p" /> <Key latin:keyStyle="deleteKeyStyle" latin:keyXPos="-10.0%p" diff --git a/java/res/xml-sw600dp/kbd_qwerty_row2.xml b/java/res/xml-sw600dp/row_qwerty2.xml index 52a948f20..cabb9cb4a 100644 --- a/java/res/xml-sw600dp/kbd_qwerty_row2.xml +++ b/java/res/xml-sw600dp/row_qwerty2.xml @@ -50,7 +50,7 @@ latin:keyLabel="l" latin:moreKeys="@string/more_keys_for_l" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-14.6%p" latin:keyWidth="fillBoth" /> </Row> diff --git a/java/res/xml-sw600dp/kbd_qwerty_row3.xml b/java/res/xml-sw600dp/row_qwerty3.xml index 4dabf633c..3d19904a1 100644 --- a/java/res/xml-sw600dp/kbd_qwerty_row3.xml +++ b/java/res/xml-sw600dp/row_qwerty3.xml @@ -46,8 +46,10 @@ <Key latin:keyLabel="m" /> <include - latin:keyboardLayout="@xml/kbd_row3_comma_period" /> + latin:keyboardLayout="@xml/keys_comma_period" /> <include - latin:keyboardLayout="@xml/kbd_row3_smiley" /> + latin:keyboardLayout="@xml/key_smiley" + latin:keyXPos="-8.9%p" + latin:keyWidth="fillBoth" /> </Row> </merge> diff --git a/java/res/xml-sw600dp/kbd_qwerty_row4.xml b/java/res/xml-sw600dp/row_qwerty4.xml index ef0292279..b06508e37 100644 --- a/java/res/xml-sw600dp/kbd_qwerty_row4.xml +++ b/java/res/xml-sw600dp/row_qwerty4.xml @@ -45,9 +45,9 @@ <default> <Key latin:keyLabel="/" - latin:keyLabelOption="hasUppercaseLetter" latin:keyHintLabel="\@" - latin:moreKeys="\@" /> + latin:moreKeys="\@" + latin:keyStyle="hasShiftedLetterHintStyle" /> </default> </switch> <Key @@ -59,18 +59,18 @@ latin:languageCode="iw" > <include - latin:keyboardLayout="@xml/kbd_row3_comma_period" /> + latin:keyboardLayout="@xml/keys_comma_period" /> </case> <!-- not languageCode="iw" --> <default> <include - latin:keyboardLayout="@xml/kbd_row4_apostrophe_dash" /> + latin:keyboardLayout="@xml/keys_apostrophe_dash" /> </default> </switch> <Spacer latin:keyXPos="-10.00%p" latin:keyWidth="0%p" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_f2" /> + latin:keyboardLayout="@xml/key_f2" /> </Row> </merge> diff --git a/java/res/xml-sw600dp/kbd_rows_arabic.xml b/java/res/xml-sw600dp/rows_arabic.xml index c2d3cd4cc..1f03968ee 100644 --- a/java/res/xml-sw600dp/kbd_rows_arabic.xml +++ b/java/res/xml-sw600dp/rows_arabic.xml @@ -22,7 +22,7 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="8.0%p" > @@ -138,44 +138,15 @@ <Key latin:keyLabel="ط" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-14.6%p" latin:keyWidth="fillBoth" /> </Row> <Row latin:keyWidth="8.0%p" > - <!-- kbd_row3_smiley --> - <switch> - <case - latin:mode="email" - > - <Key - latin:keyLabel="\@" /> - </case> - <case - latin:mode="url" - > - <Key - latin:keyLabel="-" - latin:keyLabelOption="hasUppercaseLetter" - latin:keyHintLabel="_" - latin:moreKeys="_" /> - </case> - <case - latin:imeAction="actionSearch" - > - <Key - latin:keyLabel=":" - latin:keyLabelOption="hasUppercaseLetter" - latin:keyHintLabel="+" - latin:moreKeys="+" /> - </case> - <default> - <Key - latin:keyStyle="smileyKeyStyle" /> - </default> - </switch> + <include + latin:keyboardLayout="@xml/key_smiley" /> <!-- \u0626: ARABIC LETTER YEH WITH HAMZA ABOVE --> <Key latin:keyLabel="ئ" /> @@ -213,5 +184,5 @@ latin:keyLabel="د" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml-sw600dp/kbd_rows_azerty.xml b/java/res/xml-sw600dp/rows_azerty.xml index 8ae74557c..5c799623d 100644 --- a/java/res/xml-sw600dp/kbd_rows_azerty.xml +++ b/java/res/xml-sw600dp/rows_azerty.xml @@ -22,7 +22,7 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="8.5%p" > @@ -54,8 +54,7 @@ latin:keyLabel="o" latin:moreKeys="@string/more_keys_for_o" /> <Key - latin:keyLabel="p" - latin:moreKeys="@string/more_keys_for_p" /> + latin:keyLabel="p" /> <Key latin:keyStyle="deleteKeyStyle" latin:keyXPos="-10.0%p" @@ -66,7 +65,6 @@ > <Key latin:keyLabel="q" - latin:moreKeys="@string/more_keys_for_q" latin:keyXPos="5.0%p" /> <Key latin:keyLabel="s" @@ -92,7 +90,7 @@ <Key latin:keyLabel="m" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-14.6%p" latin:keyWidth="fillBoth" /> </Row> @@ -103,8 +101,7 @@ latin:keyStyle="shiftKeyStyle" latin:keyWidth="10.0%p" /> <Key - latin:keyLabel="w" - latin:moreKeys="@string/more_keys_for_w" /> + latin:keyLabel="w" /> <Key latin:keyLabel="x" /> <Key @@ -119,32 +116,17 @@ latin:keyLabel="n" latin:moreKeys="@string/more_keys_for_n" /> <Key - latin:keyLabel="\'" /> - <switch> - <case - latin:mode="email" - > - <Key - latin:keyLabel="," /> - <Key - latin:keyLabel="." /> - </case> - <default> - <Key - latin:keyLabel="," - latin:keyLabelOption="hasUppercaseLetter" - latin:keyHintLabel="!" - latin:moreKeys="!" /> - <Key - latin:keyLabel="." - latin:keyLabelOption="hasUppercaseLetter" - latin:keyHintLabel="\?" - latin:moreKeys="\?" /> - </default> - </switch> + latin:keyLabel="\'" + latin:keyHintLabel=":" + latin:moreKeys=":" + latin:keyStyle="hasShiftedLetterHintStyle" /> <include - latin:keyboardLayout="@xml/kbd_row3_smiley" /> + latin:keyboardLayout="@xml/keys_comma_period" /> + <include + latin:keyboardLayout="@xml/key_smiley" + latin:keyXPos="-8.9%p" + latin:keyWidth="fillRight" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml-sw600dp/rows_bulgarian.xml b/java/res/xml-sw600dp/rows_bulgarian.xml new file mode 100644 index 000000000..7a23ce9ff --- /dev/null +++ b/java/res/xml-sw600dp/rows_bulgarian.xml @@ -0,0 +1,117 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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/key_styles_common" /> + <Row + latin:keyWidth="7.692%p" + > + <Key + latin:keyLabel="ч" /> + <Key + latin:keyLabel="ш" /> + <Key + latin:keyLabel="е" /> + <Key + latin:keyLabel="р" /> + <Key + latin:keyLabel="т" /> + <Key + latin:keyLabel="ъ" /> + <Key + latin:keyLabel="у" /> + <Key + latin:keyLabel="и" + latin:moreKeys="ѝ" /> + <Key + latin:keyLabel="о" /> + <Key + latin:keyLabel="п" /> + <Key + latin:keyLabel="я" /> + <Key + latin:keyStyle="deleteKeyStyle" + latin:keyWidth="fillBoth" /> + </Row> + <Row + latin:keyWidth="7.692%p" + > + <Key + latin:keyLabel="а" + latin:keyXPos="4.000%p" /> + <Key + latin:keyLabel="с" /> + <Key + latin:keyLabel="д" /> + <Key + latin:keyLabel="ф" /> + <Key + latin:keyLabel="г" /> + <Key + latin:keyLabel="х" /> + <Key + latin:keyLabel="й" /> + <Key + latin:keyLabel="к" /> + <Key + latin:keyLabel="л" /> + <Key + latin:keyLabel="щ" /> + <Key + latin:keyLabel="ь" /> + <Key + latin:keyStyle="enterKeyStyle" + latin:keyWidth="fillBoth" /> + </Row> + <Row + latin:keyWidth="7.692%p" + > + <Key + latin:keyStyle="shiftKeyStyle" + latin:keyWidth="10.000%p" /> + <Key + latin:keyLabel="з" /> + <Key + latin:keyLabel="ж" /> + <Key + latin:keyLabel="ц" /> + <Key + latin:keyLabel="в" /> + <Key + latin:keyLabel="б" /> + <Key + latin:keyLabel="н" /> + <Key + latin:keyLabel="м" /> + <Key + latin:keyLabel="ю" /> + <include + latin:keyboardLayout="@xml/keys_comma_period" /> + <include + latin:keyboardLayout="@xml/key_smiley" + latin:keyXPos="-8.9%p" + latin:keyWidth="fillRight" /> + </Row> + <include + latin:keyboardLayout="@xml/row_qwerty4" /> +</merge> diff --git a/java/res/xml-sw600dp/kbd_rows_hebrew.xml b/java/res/xml-sw600dp/rows_hebrew.xml index a8adbd34c..812e2d6e0 100644 --- a/java/res/xml-sw600dp/kbd_rows_hebrew.xml +++ b/java/res/xml-sw600dp/rows_hebrew.xml @@ -22,12 +22,12 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="9.0%p" > <include - latin:keyboardLayout="@xml/kbd_row4_apostrophe_dash" /> + latin:keyboardLayout="@xml/keys_apostrophe_dash" /> <Key latin:keyLabel="ק" /> <Key @@ -80,41 +80,9 @@ <Row latin:keyWidth="8.9%p" > - <!-- kbd_row3_smiley --> - <switch> - <case - latin:mode="email" - > - <Key - latin:keyLabel="\@" - latin:keyWidth="10.0%p" /> - </case> - <case - latin:mode="url" - > - <Key - latin:keyLabel="-" - latin:keyLabelOption="hasUppercaseLetter" - latin:keyHintLabel="_" - latin:moreKeys="_" - latin:keyWidth="10.0%p" /> - </case> - <case - latin:imeAction="actionSearch" - > - <Key - latin:keyLabel=":" - latin:keyLabelOption="hasUppercaseLetter" - latin:keyHintLabel="+" - latin:moreKeys="+" - latin:keyWidth="10.0%p" /> - </case> - <default> - <Key - latin:keyStyle="smileyKeyStyle" - latin:keyWidth="10.0%p" /> - </default> - </switch> + <include + latin:keyboardLayout="@xml/key_smiley" + latin:keyWidth="10.0%p" /> <Key latin:keyLabel="ז" latin:moreKeys="ז׳" /> @@ -138,10 +106,10 @@ latin:keyLabel="ץ" latin:moreKeys="ץ׳" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-10.400%p" latin:keyWidth="fillBoth" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml-sw600dp/rows_number_normal.xml b/java/res/xml-sw600dp/rows_number_normal.xml new file mode 100644 index 000000000..3141bbdc7 --- /dev/null +++ b/java/res/xml-sw600dp/rows_number_normal.xml @@ -0,0 +1,138 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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" +> + <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="enterKeyStyle" + 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/key_f2" /> + </Row> +</merge> diff --git a/java/res/xml-sw600dp/rows_number_password.xml b/java/res/xml-sw600dp/rows_number_password.xml new file mode 100644 index 000000000..0a71f74d7 --- /dev/null +++ b/java/res/xml-sw600dp/rows_number_password.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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" +> + <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="enterKeyStyle" + 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/key_f2" /> + </Row> +</merge> diff --git a/java/res/xml-sw600dp/kbd_phone_shift.xml b/java/res/xml-sw600dp/rows_phone.xml index 4c4f8ad12..d61b4b2ad 100644 --- a/java/res/xml-sw600dp/kbd_phone_shift.xml +++ b/java/res/xml-sw600dp/rows_phone.xml @@ -18,18 +18,17 @@ */ --> -<Keyboard +<merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyWidth="16.75%p" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <include - latin:keyboardLayout="@xml/kbd_numkey_styles" /> + latin:keyboardLayout="@xml/key_styles_number" /> <Row> <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> <Spacer - latin:keyWidth="11.00%p" /> + latin:keyWidth="12.75%p" /> <Key latin:keyLabel="-" latin:keyStyle="numKeyStyle" @@ -39,13 +38,11 @@ latin:keyStyle="numKeyStyle" latin:keyWidth="9.25%p" /> <Key - latin:code="44" - latin:keyLabel="@string/label_pause_key" - latin:keyLabelOption="followKeyHintLabelRatio|autoXScale" + latin:keyStyle="numPauseKeyStyle" latin:keyWidth="9.25%p" /> <Key latin:keyStyle="num1KeyStyle" - latin:keyXPos="38.867%p" /> + latin:keyXPos="42.25%p" /> <Key latin:keyStyle="num2KeyStyle" /> <Key @@ -53,12 +50,12 @@ <Key latin:keyStyle="deleteKeyStyle" latin:keyXPos="-11.00%p" - latin:keyWidth="fillBoth" /> + latin:keyWidth="fillRight" /> </Row> <Row> <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> <Spacer - latin:keyWidth="11.00%p" /> + latin:keyWidth="12.75%p" /> <Key latin:keyLabel="," latin:keyStyle="numKeyStyle" @@ -68,30 +65,29 @@ latin:keyStyle="numKeyStyle" latin:keyWidth="9.25%p" /> <Key - latin:code="59" - latin:keyLabel="@string/label_wait_key" - latin:keyLabelOption="followKeyHintLabelRatio|autoXScale" + latin:keyStyle="numWaitKeyStyle" latin:keyWidth="9.25%p" /> <Key latin:keyStyle="num4KeyStyle" - latin:keyXPos="38.867%p" /> + latin:keyXPos="42.25%p" /> <Key latin:keyStyle="num5KeyStyle" /> <Key latin:keyStyle="num6KeyStyle" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-11.00%p" - latin:keyWidth="fillBoth" /> + latin:keyWidth="fillRight" /> </Row> <Row> - <Key - latin:keyStyle="backFromMoreSymbolKeyStyle" - latin:keyWidth="11.00%p" /> + <!-- 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" /> + latin:keyWidth="9.25%p" + latin:keyXPos="12.75%p" /> <Key latin:keyLabel=")" latin:keyStyle="numKeyStyle" @@ -102,7 +98,7 @@ latin:keyWidth="9.25%p" /> <Key latin:keyStyle="num7KeyStyle" - latin:keyXPos="38.867%p" /> + latin:keyXPos="42.25%p" /> <Key latin:keyStyle="num8KeyStyle" /> <Key @@ -113,14 +109,15 @@ </Row> <Row> <Key - latin:keyStyle="tabKeyStyle" + latin:keyStyle="numTabKeyStyle" latin:keyWidth="11.00%p" /> <Key latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle" - latin:keyWidth="27.75%p" /> + latin:keyWidth="27.75%p" + latin:keyXPos="12.75%p" /> <Key latin:keyStyle="numStarKeyStyle" - latin:keyXPos="38.867%p" /> + latin:keyXPos="42.25%p" /> <Key latin:keyStyle="num0KeyStyle" /> <Key @@ -130,6 +127,6 @@ latin:keyXPos="-11.00%p" latin:keyWidth="0%p" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_f2" /> + latin:keyboardLayout="@xml/key_f2" /> </Row> -</Keyboard> +</merge> diff --git a/java/res/xml-sw600dp/kbd_rows_qwerty.xml b/java/res/xml-sw600dp/rows_qwerty.xml index a2d26b3de..eb41c5087 100644 --- a/java/res/xml-sw600dp/kbd_rows_qwerty.xml +++ b/java/res/xml-sw600dp/rows_qwerty.xml @@ -22,13 +22,13 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_row1" /> + latin:keyboardLayout="@xml/row_qwerty1" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_row2" /> + latin:keyboardLayout="@xml/row_qwerty2" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_row3" /> + latin:keyboardLayout="@xml/row_qwerty3" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml-sw600dp/kbd_rows_qwertz.xml b/java/res/xml-sw600dp/rows_qwertz.xml index 98667e09c..6912f1c6d 100644 --- a/java/res/xml-sw600dp/kbd_rows_qwertz.xml +++ b/java/res/xml-sw600dp/rows_qwertz.xml @@ -22,16 +22,14 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="9.0%p" > <Key - latin:keyLabel="q" - latin:moreKeys="@string/more_keys_for_q" /> + latin:keyLabel="q" /> <Key - latin:keyLabel="w" - latin:moreKeys="@string/more_keys_for_w" /> + latin:keyLabel="w" /> <Key latin:keyLabel="e" latin:moreKeys="@string/more_keys_for_e" /> @@ -54,15 +52,14 @@ latin:keyLabel="o" latin:moreKeys="@string/more_keys_for_o" /> <Key - latin:keyLabel="p" - latin:moreKeys="@string/more_keys_for_p" /> + latin:keyLabel="p" /> <Key latin:keyStyle="deleteKeyStyle" latin:keyXPos="-10.0%p" latin:keyWidth="fillBoth" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row2" /> + latin:keyboardLayout="@xml/row_qwerty2" /> <Row latin:keyWidth="8.9%p" > @@ -87,31 +84,13 @@ latin:moreKeys="@string/more_keys_for_n" /> <Key latin:keyLabel="m" /> - <switch> - <case - latin:mode="email" - > - <Key - latin:keyLabel="," /> - <Key - latin:keyLabel="." /> - </case> - <default> - <Key - latin:keyLabel="," - latin:keyLabelOption="hasUppercaseLetter" - latin:keyHintLabel="!" - latin:moreKeys="!" /> - <Key - latin:keyLabel="." - latin:keyLabelOption="hasUppercaseLetter" - latin:keyHintLabel="\?" - latin:moreKeys="\?" /> - </default> - </switch> <include - latin:keyboardLayout="@xml/kbd_row3_smiley" /> + latin:keyboardLayout="@xml/keys_comma_period" /> + <include + latin:keyboardLayout="@xml/key_smiley" + latin:keyXPos="-8.9%p" + latin:keyWidth="fillBoth" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml-sw600dp/kbd_rows_scandinavian.xml b/java/res/xml-sw600dp/rows_scandinavian.xml index 19fb5212b..912c40658 100644 --- a/java/res/xml-sw600dp/kbd_rows_scandinavian.xml +++ b/java/res/xml-sw600dp/rows_scandinavian.xml @@ -22,16 +22,14 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="7.9%p" > <Key - latin:keyLabel="q" - latin:moreKeys="@string/more_keys_for_q" /> + latin:keyLabel="q" /> <Key - latin:keyLabel="w" - latin:moreKeys="@string/more_keys_for_w" /> + latin:keyLabel="w" /> <Key latin:keyLabel="e" latin:moreKeys="@string/more_keys_for_e" /> @@ -54,10 +52,9 @@ latin:keyLabel="o" latin:moreKeys="@string/more_keys_for_o" /> <Key - latin:keyLabel="p" - latin:moreKeys="@string/more_keys_for_p" /> + latin:keyLabel="p" /> <Key - latin:keyLabel="å" /> + latin:keyLabel="@string/keylabel_for_scandinavia_row1_11" /> <Key latin:keyStyle="deleteKeyStyle" latin:keyXPos="-10.0%p" @@ -98,7 +95,7 @@ latin:keyLabel="@string/keylabel_for_scandinavia_row2_11" latin:moreKeys="@string/more_keys_for_scandinavia_row2_11" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-14.6%p" latin:keyWidth="fillBoth" /> </Row> @@ -129,12 +126,12 @@ <Key latin:keyLabel="m" /> <include - latin:keyboardLayout="@xml/kbd_row3_comma_period" /> - <Spacer - latin:keyWidth="4.35%p" /> + latin:keyboardLayout="@xml/keys_comma_period" /> <include - latin:keyboardLayout="@xml/kbd_row3_smiley" /> + latin:keyboardLayout="@xml/key_smiley" + latin:keyXPos="-8.9%p" + latin:keyWidth="fillRight" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml-sw600dp/kbd_rows_serbian.xml b/java/res/xml-sw600dp/rows_serbian.xml index db7560cdc..ea4bb1466 100644 --- a/java/res/xml-sw600dp/kbd_rows_serbian.xml +++ b/java/res/xml-sw600dp/rows_serbian.xml @@ -22,7 +22,7 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="8.0%p" > @@ -80,7 +80,7 @@ <Key latin:keyLabel="ћ" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-14.6%p" latin:keyWidth="fillBoth" /> </Row> @@ -109,10 +109,12 @@ <Key latin:keyLabel="ж" /> <include - latin:keyboardLayout="@xml/kbd_row3_comma_period" /> + latin:keyboardLayout="@xml/keys_comma_period" /> <include - latin:keyboardLayout="@xml/kbd_row3_smiley" /> + latin:keyboardLayout="@xml/key_smiley" + latin:keyXPos="-8.9%p" + latin:keyWidth="fillBoth" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml-sw600dp/kbd_rows_russian.xml b/java/res/xml-sw600dp/rows_slavic.xml index cc9ad3aa7..020ea16a2 100644 --- a/java/res/xml-sw600dp/kbd_rows_russian.xml +++ b/java/res/xml-sw600dp/rows_slavic.xml @@ -22,7 +22,7 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="7.60%p" > @@ -31,20 +31,22 @@ <Key latin:keyLabel="ц" /> <Key - latin:keyLabel="у" /> + latin:keyLabel="у" + latin:moreKeys="@string/more_keys_for_slavic_u" /> <Key latin:keyLabel="к" /> <Key latin:keyLabel="е" - latin:moreKeys="@string/more_keys_for_cyrillic_e" /> + latin:moreKeys="@string/more_keys_for_slavic_ye" /> <Key - latin:keyLabel="н" /> + latin:keyLabel="н" + latin:moreKeys="@string/more_keys_for_slavic_en" /> <Key latin:keyLabel="г" /> <Key latin:keyLabel="ш" /> <Key - latin:keyLabel="щ" /> + latin:keyLabel="@string/keylabel_for_slavic_shcha" /> <Key latin:keyLabel="з" /> <Key @@ -63,7 +65,8 @@ latin:keyLabel="ф" latin:keyXPos="2.25%p" /> <Key - latin:keyLabel="ы" /> + latin:keyLabel="@string/keylabel_for_slavic_yery" + latin:moreKeys="@string/more_keys_for_slavic_yery" /> <Key latin:keyLabel="в" /> <Key @@ -73,7 +76,8 @@ <Key latin:keyLabel="р" /> <Key - latin:keyLabel="о" /> + latin:keyLabel="о" + latin:moreKeys="@string/more_keys_for_slavic_o" /> <Key latin:keyLabel="л" /> <Key @@ -83,7 +87,7 @@ <Key latin:keyLabel="э" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-14.6%p" latin:keyWidth="fillBoth" /> </Row> @@ -101,7 +105,7 @@ <Key latin:keyLabel="м" /> <Key - latin:keyLabel="и" /> + latin:keyLabel="@string/keylabel_for_slavic_i" /> <Key latin:keyLabel="т" /> <Key @@ -110,31 +114,13 @@ latin:keyLabel="б" /> <Key latin:keyLabel="ю" /> - <switch> - <case - latin:mode="email" - > - <Key - latin:keyLabel="," /> - <Key - latin:keyLabel="." /> - </case> - <default> - <Key - latin:keyLabel="," - latin:keyLabelOption="hasUppercaseLetter" - latin:keyHintLabel="!" - latin:moreKeys="!" /> - <Key - latin:keyLabel="." - latin:keyLabelOption="hasUppercaseLetter" - latin:keyHintLabel="\?" - latin:moreKeys="\?" /> - </default> - </switch> <include - latin:keyboardLayout="@xml/kbd_row3_smiley" /> + latin:keyboardLayout="@xml/keys_comma_period" /> + <include + latin:keyboardLayout="@xml/key_smiley" + latin:keyXPos="-8.9%p" + latin:keyWidth="fillBoth" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml-sw600dp/kbd_rows_spanish.xml b/java/res/xml-sw600dp/rows_spanish.xml index 8506af697..2ab94e8c5 100644 --- a/java/res/xml-sw600dp/kbd_rows_spanish.xml +++ b/java/res/xml-sw600dp/rows_spanish.xml @@ -22,9 +22,9 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_row1" /> + latin:keyboardLayout="@xml/row_qwerty1" /> <Row latin:keyWidth="8.5%p" > @@ -56,12 +56,12 @@ <Key latin:keyLabel="ñ" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-14.6%p" latin:keyWidth="fillBoth" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row3" /> + latin:keyboardLayout="@xml/row_qwerty3" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml-sw600dp/kbd_rows_symbols.xml b/java/res/xml-sw600dp/rows_symbols.xml index bb48fe734..ce6e539a5 100644 --- a/java/res/xml-sw600dp/kbd_rows_symbols.xml +++ b/java/res/xml-sw600dp/rows_symbols.xml @@ -22,41 +22,51 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <include - latin:keyboardLayout="@xml/kbd_currency_key_styles" /> + latin:keyboardLayout="@xml/key_styles_currency" /> <Row latin:keyWidth="9.0%p" > <Key latin:keyLabel="@string/keylabel_for_symbols_1" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_1" latin:moreKeys="@string/more_keys_for_symbols_1" /> <Key latin:keyLabel="@string/keylabel_for_symbols_2" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_2" latin:moreKeys="@string/more_keys_for_symbols_2" /> <Key latin:keyLabel="@string/keylabel_for_symbols_3" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_3" latin:moreKeys="@string/more_keys_for_symbols_3" /> <Key latin:keyLabel="@string/keylabel_for_symbols_4" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_4" latin:moreKeys="@string/more_keys_for_symbols_4" /> <Key latin:keyLabel="@string/keylabel_for_symbols_5" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_5" latin:moreKeys="@string/more_keys_for_symbols_5" /> <Key latin:keyLabel="@string/keylabel_for_symbols_6" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_6" latin:moreKeys="@string/more_keys_for_symbols_6" /> <Key latin:keyLabel="@string/keylabel_for_symbols_7" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_7" latin:moreKeys="@string/more_keys_for_symbols_7" /> <Key latin:keyLabel="@string/keylabel_for_symbols_8" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_8" latin:moreKeys="@string/more_keys_for_symbols_8" /> <Key latin:keyLabel="@string/keylabel_for_symbols_9" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_9" latin:moreKeys="@string/more_keys_for_symbols_9" /> <Key latin:keyLabel="@string/keylabel_for_symbols_0" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_0" latin:moreKeys="@string/more_keys_for_symbols_0" /> <Key latin:keyStyle="deleteKeyStyle" @@ -85,14 +95,10 @@ <Key latin:keyLabel="+" latin:moreKeys="@string/more_keys_for_plus" /> + <include + latin:keyboardLayout="@xml/keys_parentheses" /> <Key - latin:keyLabel="(" - latin:moreKeys="[,{,<" /> - <Key - latin:keyLabel=")" - latin:moreKeys="],},>" /> - <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-14.6%p" latin:keyWidth="fillBoth" /> </Row> @@ -102,12 +108,8 @@ <Key latin:keyStyle="toMoreSymbolKeyStyle" latin:keyWidth="10.0%p" /> - <Key - latin:keyLabel="<" - latin:moreKeys="≤,«,‹" /> - <Key - latin:keyLabel=">" - latin:moreKeys="≥,»,›" /> + <include + latin:keyboardLayout="@xml/keys_less_greater" /> <Key latin:keyLabel="=" latin:moreKeys="≠,≈" /> @@ -116,8 +118,7 @@ latin:mode="url" > <Key - latin:keyLabel="\'" - latin:moreKeys="‘,’,‚,‛" /> + latin:keyLabel="\'" /> </case> <default> <Key @@ -156,17 +157,16 @@ latin:keyStyle="spaceKeyStyle" latin:keyXPos="30.750%p" latin:keyWidth="39.750%p" /> - <!-- Note: DroidSans doesn't have double-high-reversed-quotation '\u201f' glyph. --> - <!-- latin:moreKeys="“,”,„,‟,«,»,‘,’,‚,‛" --> <Key latin:keyLabel=""" - latin:moreKeys="“,”,«,»,‘,’,‚,‛" /> + latin:moreKeys="@string/more_keys_for_tablet_double_quote" + latin:maxMoreKeysColumn="4" /> <Key latin:keyLabel="_" /> <Spacer latin:keyXPos="-10.00%p" latin:keyWidth="0%p" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_f2" /> + latin:keyboardLayout="@xml/key_f2" /> </Row> </merge> diff --git a/java/res/xml-sw600dp/kbd_rows_symbols_shift.xml b/java/res/xml-sw600dp/rows_symbols_shift.xml index 8e4751502..a10d1740c 100644 --- a/java/res/xml-sw600dp/kbd_rows_symbols_shift.xml +++ b/java/res/xml-sw600dp/rows_symbols_shift.xml @@ -22,9 +22,9 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <include - latin:keyboardLayout="@xml/kbd_currency_key_styles" /> + latin:keyboardLayout="@xml/key_styles_currency" /> <Row latin:keyWidth="9.0%p" > @@ -77,12 +77,10 @@ <Key latin:keyLabel="±" latin:moreKeys="∞" /> + <include + latin:keyboardLayout="@xml/keys_curly_brackets" /> <Key - latin:keyLabel="{" /> - <Key - latin:keyLabel="}" /> - <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-14.6%p" latin:keyWidth="fillBoth" /> </Row> @@ -102,10 +100,8 @@ latin:keyLabel="™" /> <Key latin:keyLabel="℅" /> - <Key - latin:keyLabel="[" /> - <Key - latin:keyLabel="]" /> + <include + latin:keyboardLayout="@xml/keys_square_brackets" /> <Key latin:keyLabel="¡" /> <Key @@ -127,6 +123,6 @@ latin:keyXPos="-10.00%p" latin:keyWidth="0%p" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_f2" /> + latin:keyboardLayout="@xml/key_f2" /> </Row> </merge> diff --git a/java/res/xml-sw768dp-land/kbd_mini_keyboard_template.xml b/java/res/xml-sw768dp-land/kbd_more_keys_keyboard_template.xml index 85e864a6c..f593fa944 100644 --- a/java/res/xml-sw768dp-land/kbd_mini_keyboard_template.xml +++ b/java/res/xml-sw768dp-land/kbd_more_keys_keyboard_template.xml @@ -21,6 +21,6 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" latin:keyWidth="3.5%p" latin:rowHeight="@dimen/popup_key_height" - style="?attr/miniKeyboardStyle" + style="?attr/moreKeysKeyboardStyle" > </Keyboard> 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..3ad25a392 --- /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/rows_number" /> +</Keyboard> diff --git a/java/res/xml-ar/kbd_symbols_shift.xml b/java/res/xml-sw768dp-land/kbd_phone.xml index 934e6f849..abe7e7c41 100644 --- a/java/res/xml-ar/kbd_symbols_shift.xml +++ b/java/res/xml-sw768dp-land/kbd_phone.xml @@ -20,8 +20,9 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:isRtlKeyboard="true" + latin:keyboardHorizontalEdgesPadding="10%p" + latin:keyWidth="13.250%p" > <include - latin:keyboardLayout="@xml/kbd_rows_symbols_shift" /> + latin:keyboardLayout="@xml/rows_phone" /> </Keyboard> diff --git a/java/res/xml-sw768dp-land/kbd_phone_symbols.xml b/java/res/xml-sw768dp-land/kbd_phone_symbols.xml new file mode 100644 index 000000000..641464dbe --- /dev/null +++ b/java/res/xml-sw768dp-land/kbd_phone_symbols.xml @@ -0,0 +1,29 @@ +<?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" +> + <!-- Tablet doesn't have phone symbols keyboard --> + <include + latin:keyboardLayout="@xml/rows_phone" /> +</Keyboard> diff --git a/java/res/xml-sw768dp/kbd_mini_keyboard_template.xml b/java/res/xml-sw768dp/kbd_more_keys_keyboard_template.xml index 409c60556..f89a0a673 100644 --- a/java/res/xml-sw768dp/kbd_mini_keyboard_template.xml +++ b/java/res/xml-sw768dp/kbd_more_keys_keyboard_template.xml @@ -21,6 +21,6 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" latin:keyWidth="5.0%p" latin:rowHeight="@dimen/popup_key_height" - style="?attr/miniKeyboardStyle" + style="?attr/moreKeysKeyboardStyle" > </Keyboard> diff --git a/java/res/xml-sw768dp/kbd_number.xml b/java/res/xml-sw768dp/kbd_number.xml index 369e91a77..b20123c80 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/rows_number" /> </Keyboard> diff --git a/java/res/xml-sw768dp/kbd_phone.xml b/java/res/xml-sw768dp/kbd_phone.xml index e55b1841a..fa9bf1bf4 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/rows_phone" /> </Keyboard> diff --git a/java/res/xml-da/kbd_qwerty.xml b/java/res/xml-sw768dp/kbd_phone_symbols.xml index 37a50fdfd..e1a359e84 100644 --- a/java/res/xml-da/kbd_qwerty.xml +++ b/java/res/xml-sw768dp/kbd_phone_symbols.xml @@ -20,8 +20,9 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyboardLocale="da" + latin:keyWidth="13.250%p" > + <!-- Tablet doesn't have phone symbols keyboard --> <include - latin:keyboardLayout="@xml/kbd_rows_scandinavian" /> + latin:keyboardLayout="@xml/rows_phone" /> </Keyboard> diff --git a/java/res/xml-sw768dp/kbd_row3_comma_period.xml b/java/res/xml-sw768dp/kbd_row3_comma_period.xml deleted file mode 100644 index b84443078..000000000 --- a/java/res/xml-sw768dp/kbd_row3_comma_period.xml +++ /dev/null @@ -1,46 +0,0 @@ -<?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" -> - <switch> - <case - latin:mode="email" - > - <Key - latin:keyLabel="," /> - <Key - latin:keyLabel="." /> - </case> - <default> - <Key - latin:keyLabel="," - latin:keyLabelOption="hasUppercaseLetter" - latin:keyHintLabel="!" - latin:moreKeys="!" /> - <Key - latin:keyLabel="." - latin:keyLabelOption="hasUppercaseLetter" - latin:keyHintLabel="\?" - latin:moreKeys="\?" /> - </default> - </switch> -</merge> diff --git a/java/res/xml-sw768dp/kbd_key_styles.xml b/java/res/xml-sw768dp/key_styles_common.xml index f16f5b6af..07bdd7b18 100644 --- a/java/res/xml-sw768dp/kbd_key_styles.xml +++ b/java/res/xml-sw768dp/key_styles_common.xml @@ -21,80 +21,125 @@ <merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > - <key-style - latin:styleName="shiftKeyStyle" - latin:code="@integer/key_shift" - latin:keyIcon="iconShiftKey" - latin:keyIconShifted="iconShiftedShiftKey" - latin:backgroundType="sticky" /> + <switch> + <case + latin:keyboardSetElement="alphabetManualShifted|alphabetShiftLockShifted" + > + <key-style + latin:styleName="hasShiftedLetterHintStyle" + latin:keyLabelFlags="hasShiftedLetterHint|shiftedLetterActivated" /> + </case> + <default> + <key-style + latin:styleName="hasShiftedLetterHintStyle" + latin:keyLabelFlags="hasShiftedLetterHint" /> + </default> + </switch> + <switch> + <case + latin:keyboardSetElement="alphabetManualShifted|alphabetAutomaticShifted" + > + <key-style + latin:styleName="shiftKeyStyle" + latin:code="@integer/key_shift" + latin:keyIcon="iconShiftKeyShifted" + latin:keyActionFlags="noKeyPreview" + latin:backgroundType="stickyOff" /> + </case> + <case + latin:keyboardSetElement="alphabetShiftLocked|alphabetShiftLockShifted" + > + <key-style + latin:styleName="shiftKeyStyle" + latin:code="@integer/key_shift" + latin:keyIcon="iconShiftKeyShifted" + latin:keyActionFlags="noKeyPreview" + latin:backgroundType="stickyOn" /> + </case> + <default> + <key-style + latin:styleName="shiftKeyStyle" + latin:code="@integer/key_shift" + latin:keyIcon="iconShiftKey" + latin:keyActionFlags="noKeyPreview" + latin:backgroundType="stickyOff" /> + </default> + </switch> <key-style latin:styleName="deleteKeyStyle" latin:code="@integer/key_delete" latin:keyIcon="iconDeleteKey" - latin:backgroundType="functional" - latin:isRepeatable="true" /> - <key-style - latin:styleName="returnKeyStyle" - latin:code="@integer/key_return" - latin:keyIcon="iconReturnKey" + latin:keyActionFlags="isRepeatable|noKeyPreview" latin:backgroundType="functional" /> + <include + latin:keyboardLayout="@xml/key_styles_enter_tablet" /> <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|preserveCase" 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:keyIconDisabled="iconDisabledShortcutKey" + latin:keyLabelFlags="preserveCase" + latin:keyActionFlags="noKeyPreview|altCodeWhileTyping" + latin:backgroundType="functional" /> + <key-style + latin:styleName="settingsKeyStyle" + latin:code="@integer/key_settings" + latin:keyIcon="iconSettingsKey" + latin:keyActionFlags="noKeyPreview|altCodeWhileTyping" 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|preserveCase" 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|preserveCase" + 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|preserveCase" + 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|preserveCase" + 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|preserveCase" + 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|preserveCase" latin:keyOutputText="@string/keylabel_for_popular_domain" latin:moreKeys="@string/more_keys_for_popular_domain" /> </merge> diff --git a/java/res/xml-sw600dp/kbd_row4_apostrophe_dash.xml b/java/res/xml-sw768dp/keys_apostrophe_dash.xml index 9536e81da..a53c1e4ab 100644 --- a/java/res/xml-sw600dp/kbd_row4_apostrophe_dash.xml +++ b/java/res/xml-sw768dp/keys_apostrophe_dash.xml @@ -33,16 +33,16 @@ > <Key latin:keyLabel="/" - latin:keyLabelOption="hasUppercaseLetter" latin:keyHintLabel=":" - latin:moreKeys=":" /> + latin:moreKeys=":" + latin:keyStyle="hasShiftedLetterHintStyle" /> </case> <default> <Key latin:keyLabel="@string/keylabel_for_apostrophe" - latin:keyLabelOption="hasUppercaseLetter" latin:keyHintLabel="@string/keyhintlabel_for_apostrophe" - latin:moreKeys="@string/more_keys_for_apostrophe" /> + latin:moreKeys="@string/more_keys_for_apostrophe" + latin:keyStyle="hasShiftedLetterHintStyle" /> </default> </switch> <switch> @@ -55,9 +55,9 @@ <default> <Key latin:keyLabel="@string/keylabel_for_dash" - latin:keyLabelOption="hasUppercaseLetter" latin:keyHintLabel="@string/keyhintlabel_for_dash" - latin:moreKeys="@string/more_keys_for_dash" /> + latin:moreKeys="@string/more_keys_for_dash" + latin:keyStyle="hasShiftedLetterHintStyle" /> </default> </switch> </merge> diff --git a/java/res/xml-sw768dp/kbd_qwerty_row1.xml b/java/res/xml-sw768dp/row_qwerty1.xml index 14b8bddfb..f6600ad03 100644 --- a/java/res/xml-sw768dp/kbd_qwerty_row1.xml +++ b/java/res/xml-sw768dp/row_qwerty1.xml @@ -26,14 +26,12 @@ > <Key latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="7.969%p" /> <Key - latin:keyLabel="q" - latin:moreKeys="@string/more_keys_for_q" /> + latin:keyLabel="q" /> <Key - latin:keyLabel="w" - latin:moreKeys="@string/more_keys_for_w" /> + latin:keyLabel="w" /> <Key latin:keyLabel="e" latin:moreKeys="@string/more_keys_for_e" /> @@ -56,8 +54,7 @@ latin:keyLabel="o" latin:moreKeys="@string/more_keys_for_o" /> <Key - latin:keyLabel="p" - latin:moreKeys="@string/more_keys_for_p" /> + latin:keyLabel="p" /> <Key latin:keyStyle="deleteKeyStyle" latin:keyXPos="-9.219%p" diff --git a/java/res/xml-sw768dp/kbd_qwerty_row2.xml b/java/res/xml-sw768dp/row_qwerty2.xml index 2c312a328..d348041fd 100644 --- a/java/res/xml-sw768dp/kbd_qwerty_row2.xml +++ b/java/res/xml-sw768dp/row_qwerty2.xml @@ -26,7 +26,7 @@ > <Key latin:keyStyle="toSymbolKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="11.172%p"/> <Key latin:keyLabel="a" @@ -53,7 +53,7 @@ latin:keyLabel="l" latin:moreKeys="@string/more_keys_for_l" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-15.704%p" latin:keyWidth="fillBoth" /> </Row> diff --git a/java/res/xml-sw768dp/kbd_qwerty_row3.xml b/java/res/xml-sw768dp/row_qwerty3.xml index f2f137ea9..e2bb2e546 100644 --- a/java/res/xml-sw768dp/kbd_qwerty_row3.xml +++ b/java/res/xml-sw768dp/row_qwerty3.xml @@ -46,7 +46,7 @@ <Key latin:keyLabel="m" /> <include - latin:keyboardLayout="@xml/kbd_row3_comma_period" /> + latin:keyboardLayout="@xml/keys_comma_period" /> <Key latin:keyStyle="shiftKeyStyle" latin:keyXPos="-13.750%p" diff --git a/java/res/xml-sw768dp/kbd_qwerty_row4.xml b/java/res/xml-sw768dp/row_qwerty4.xml index e35e47d83..84c4a37f0 100644 --- a/java/res/xml-sw768dp/kbd_qwerty_row4.xml +++ b/java/res/xml-sw768dp/row_qwerty4.xml @@ -57,9 +57,9 @@ > <Key latin:keyLabel=":" - latin:keyLabelOption="hasUppercaseLetter" latin:keyHintLabel="+" - latin:moreKeys="+" /> + latin:moreKeys="+" + latin:keyStyle="hasShiftedLetterHintStyle" /> </case> <default> <Key @@ -76,9 +76,9 @@ <default> <Key latin:keyLabel="/" - latin:keyLabelOption="hasUppercaseLetter" latin:keyHintLabel="\@" - latin:moreKeys="\@" /> + latin:moreKeys="\@" + latin:keyStyle="hasShiftedLetterHintStyle" /> </default> </switch> </default> @@ -92,11 +92,11 @@ latin:languageCode="iw" > <include - latin:keyboardLayout="@xml/kbd_row3_comma_period" /> + latin:keyboardLayout="@xml/keys_comma_period" /> </case> <default> <include - latin:keyboardLayout="@xml/kbd_row4_apostrophe_dash" /> + latin:keyboardLayout="@xml/keys_apostrophe_dash" /> </default> </switch> <switch> diff --git a/java/res/xml-sw768dp/kbd_rows_arabic.xml b/java/res/xml-sw768dp/rows_arabic.xml index 7ec36fd94..baced66c3 100644 --- a/java/res/xml-sw768dp/kbd_rows_arabic.xml +++ b/java/res/xml-sw768dp/rows_arabic.xml @@ -22,13 +22,13 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="7.375%p" > <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 --> @@ -144,7 +144,7 @@ <Key latin:keyLabel="ط" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-9.375%p" latin:keyWidth="fillBoth" /> </Row> @@ -189,5 +189,5 @@ latin:keyLabel="د" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml-sw768dp/kbd_rows_azerty.xml b/java/res/xml-sw768dp/rows_azerty.xml index 4659d9924..6023e984b 100644 --- a/java/res/xml-sw768dp/kbd_rows_azerty.xml +++ b/java/res/xml-sw768dp/rows_azerty.xml @@ -22,13 +22,13 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="8.282%p" > <Key latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="7.969%p" /> <Key latin:keyLabel="a" @@ -58,8 +58,7 @@ latin:keyLabel="o" latin:moreKeys="@string/more_keys_for_o" /> <Key - latin:keyLabel="p" - latin:moreKeys="@string/more_keys_for_p" /> + latin:keyLabel="p" /> <Key latin:keyStyle="deleteKeyStyle" latin:keyXPos="-9.219%p" @@ -70,11 +69,10 @@ > <Key latin:keyStyle="toSymbolKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="10.167%p" /> <Key - latin:keyLabel="q" - latin:moreKeys="@string/more_keys_for_q" /> + latin:keyLabel="q" /> <Key latin:keyLabel="s" latin:moreKeys="@string/more_keys_for_s" /> @@ -99,7 +97,7 @@ <Key latin:keyLabel="m" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-15.704%p" latin:keyWidth="fillBoth" /> </Row> @@ -110,8 +108,7 @@ latin:keyStyle="shiftKeyStyle" latin:keyWidth="13.829%p" /> <Key - latin:keyLabel="w" - latin:moreKeys="@string/more_keys_for_w" /> + latin:keyLabel="w" /> <Key latin:keyLabel="x" /> <Key @@ -127,36 +124,16 @@ latin:moreKeys="@string/more_keys_for_n" /> <Key latin:keyLabel="\'" - latin:keyLabelOption="hasUppercaseLetter" latin:keyHintLabel=":" - latin:moreKeys=":" /> - <switch> - <case - latin:mode="email" - > - <Key - latin:keyLabel="," /> - <Key - latin:keyLabel="." /> - </case> - <default> - <Key - latin:keyLabel="," - latin:keyLabelOption="hasUppercaseLetter" - latin:keyHintLabel="!" - latin:moreKeys="!" /> - <Key - latin:keyLabel="." - latin:keyLabelOption="hasUppercaseLetter" - latin:keyHintLabel="\?" - latin:moreKeys="\?" /> - </default> - </switch> + latin:moreKeys=":" + latin:keyStyle="hasShiftedLetterHintStyle" /> + <include + latin:keyboardLayout="@xml/keys_comma_period" /> <Key latin:keyStyle="shiftKeyStyle" latin:keyXPos="-13.750%p" latin:keyWidth="fillBoth" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml-sw768dp/kbd_rows_russian.xml b/java/res/xml-sw768dp/rows_bulgarian.xml index e5f556958..d67a0d1fa 100644 --- a/java/res/xml-sw768dp/kbd_rows_russian.xml +++ b/java/res/xml-sw768dp/rows_bulgarian.xml @@ -2,7 +2,7 @@ <!-- /* ** -** Copyright 2011, The Android Open Source Project +** Copyright 2012, 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. @@ -22,74 +22,71 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row - latin:keyWidth="7.125%p" + latin:keyWidth="7.333%p" > <Key latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" /> + latin:keyLabelFlags="alignLeft" /> <Key - latin:keyLabel="й" /> + latin:keyLabel="ч" /> <Key - latin:keyLabel="ц" /> + latin:keyLabel="ш" /> <Key - latin:keyLabel="у" /> + latin:keyLabel="е" /> <Key - latin:keyLabel="к" /> + latin:keyLabel="р" /> <Key - latin:keyLabel="е" - latin:moreKeys="@string/more_keys_for_cyrillic_e" /> + latin:keyLabel="т" /> <Key - latin:keyLabel="н" /> + latin:keyLabel="ъ" /> <Key - latin:keyLabel="г" /> + latin:keyLabel="у" /> <Key - latin:keyLabel="ш" /> + latin:keyLabel="и" + latin:moreKeys="ѝ" /> <Key - latin:keyLabel="щ" /> - <Key - latin:keyLabel="з" /> + latin:keyLabel="о" /> <Key - latin:keyLabel="х" /> + latin:keyLabel="п" /> <Key - latin:keyLabel="ъ" /> + latin:keyLabel="я" /> <Key latin:keyStyle="deleteKeyStyle" latin:keyWidth="fillBoth" /> </Row> <Row - latin:keyWidth="7.125%p" + latin:keyWidth="7.194%p" > <Key latin:keyStyle="toSymbolKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="9.375%p" /> <Key - latin:keyLabel="ф" /> + latin:keyLabel="а" /> <Key - latin:keyLabel="ы" /> + latin:keyLabel="с" /> <Key - latin:keyLabel="в" /> + latin:keyLabel="д" /> <Key - latin:keyLabel="а" /> + latin:keyLabel="ф" /> <Key - latin:keyLabel="п" /> + latin:keyLabel="г" /> <Key - latin:keyLabel="р" /> + latin:keyLabel="х" /> <Key - latin:keyLabel="о" /> + latin:keyLabel="й" /> <Key - latin:keyLabel="л" /> + latin:keyLabel="к" /> <Key - latin:keyLabel="д" /> + latin:keyLabel="л" /> <Key - latin:keyLabel="ж" /> + latin:keyLabel="щ" /> <Key - latin:keyLabel="э" /> + latin:keyLabel="ь" /> <Key - latin:keyStyle="returnKeyStyle" - latin:keyXPos="-9.375%p" + latin:keyStyle="enterKeyStyle" latin:keyWidth="fillBoth" /> </Row> <Row @@ -97,31 +94,29 @@ > <Key latin:keyStyle="shiftKeyStyle" - latin:keyWidth="12.750%p" /> + latin:keyWidth="14.375%p" /> <Key - latin:keyLabel="я" /> - <Key - latin:keyLabel="ч" /> + latin:keyLabel="з" /> <Key - latin:keyLabel="с" /> + latin:keyLabel="ж" /> <Key - latin:keyLabel="м" /> + latin:keyLabel="ц" /> <Key - latin:keyLabel="и" /> + latin:keyLabel="в" /> <Key - latin:keyLabel="т" /> + latin:keyLabel="б" /> <Key - latin:keyLabel="ь" /> + latin:keyLabel="н" /> <Key - latin:keyLabel="б" /> + latin:keyLabel="м" /> <Key latin:keyLabel="ю" /> <include - latin:keyboardLayout="@xml/kbd_row3_comma_period" /> + latin:keyboardLayout="@xml/keys_comma_period" /> <Key latin:keyStyle="shiftKeyStyle" latin:keyWidth="fillBoth" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml-sw768dp/kbd_rows_hebrew.xml b/java/res/xml-sw768dp/rows_hebrew.xml index 27b39d1ae..61c5eae90 100644 --- a/java/res/xml-sw768dp/kbd_rows_hebrew.xml +++ b/java/res/xml-sw768dp/rows_hebrew.xml @@ -22,16 +22,16 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="8.282%p" > <Key latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="7.969%p" /> <include - latin:keyboardLayout="@xml/kbd_row4_apostrophe_dash" /> + latin:keyboardLayout="@xml/keys_apostrophe_dash" /> <Key latin:keyLabel="ק" /> <Key @@ -58,7 +58,7 @@ > <Key latin:keyStyle="toSymbolKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="11.172%p" /> <Key latin:keyLabel="ש" /> @@ -111,10 +111,10 @@ latin:keyLabel="ץ" latin:moreKeys="ץ׳" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-10.400%p" latin:keyWidth="fillBoth" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml-sw768dp/rows_number_normal.xml b/java/res/xml-sw768dp/rows_number_normal.xml new file mode 100644 index 000000000..cf947abd2 --- /dev/null +++ b/java/res/xml-sw768dp/rows_number_normal.xml @@ -0,0 +1,159 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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" +> + <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="enterKeyStyle" + 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> +</merge> diff --git a/java/res/xml-sw768dp/rows_number_password.xml b/java/res/xml-sw768dp/rows_number_password.xml new file mode 100644 index 000000000..8acfac6ff --- /dev/null +++ b/java/res/xml-sw768dp/rows_number_password.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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" +> + <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="enterKeyStyle" + 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> +</merge> diff --git a/java/res/xml-sw768dp/kbd_phone_shift.xml b/java/res/xml-sw768dp/rows_phone.xml index 46f67d311..0404bb1fb 100644 --- a/java/res/xml-sw768dp/kbd_phone_shift.xml +++ b/java/res/xml-sw768dp/rows_phone.xml @@ -2,7 +2,7 @@ <!-- /* ** -** Copyright 2010, The Android Open Source Project +** 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. @@ -18,18 +18,17 @@ */ --> -<Keyboard +<merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyWidth="13.250%p" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <include - latin:keyboardLayout="@xml/kbd_numkey_styles" /> + latin:keyboardLayout="@xml/key_styles_number" /> <Row> <Key - latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyStyle="numTabKeyStyle" + latin:keyLabelFlags="alignLeft" latin:keyWidth="11.172%p" /> <Key latin:keyLabel="-" @@ -41,9 +40,7 @@ latin:keyStyle="numKeyStyle" latin:keyWidth="8.047%p" /> <Key - latin:code="44" - latin:keyLabel="@string/label_pause_key" - latin:keyLabelOption="followKeyHintLabelRatio|autoXScale" + latin:keyStyle="numPauseKeyStyle" latin:keyWidth="8.047%p" /> <Key latin:keyStyle="num1KeyStyle" @@ -58,9 +55,9 @@ latin:keyWidth="fillRight" /> </Row> <Row> - <Key - latin:keyStyle="backFromMoreSymbolKeyStyle" - latin:keyWidth="11.172%p" /> + <!-- 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" @@ -71,9 +68,7 @@ latin:keyStyle="numKeyStyle" latin:keyWidth="8.047%p" /> <Key - latin:code="59" - latin:keyLabel="@string/label_wait_key" - latin:keyLabelOption="followKeyHintLabelRatio|autoXScale" + latin:keyStyle="numWaitKeyStyle" latin:keyWidth="8.047%p" /> <Key latin:keyStyle="num4KeyStyle" @@ -83,7 +78,7 @@ <Key latin:keyStyle="num6KeyStyle" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-11.172%p" latin:keyWidth="fillRight" /> </Row> @@ -155,4 +150,4 @@ </default> </switch> </Row> -</Keyboard> +</merge> diff --git a/java/res/xml-sw768dp/kbd_rows_qwerty.xml b/java/res/xml-sw768dp/rows_qwerty.xml index 6237712f6..71be44e31 100644 --- a/java/res/xml-sw768dp/kbd_rows_qwerty.xml +++ b/java/res/xml-sw768dp/rows_qwerty.xml @@ -22,13 +22,13 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_row1" /> + latin:keyboardLayout="@xml/row_qwerty1" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_row2" /> + latin:keyboardLayout="@xml/row_qwerty2" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_row3" /> + latin:keyboardLayout="@xml/row_qwerty3" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml-sw768dp/kbd_rows_qwertz.xml b/java/res/xml-sw768dp/rows_qwertz.xml index 82e0dd09c..7056a94ea 100644 --- a/java/res/xml-sw768dp/kbd_rows_qwertz.xml +++ b/java/res/xml-sw768dp/rows_qwertz.xml @@ -22,20 +22,18 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="8.282%p" > <Key latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="7.969%p" /> <Key - latin:keyLabel="q" - latin:moreKeys="@string/more_keys_for_q" /> + latin:keyLabel="q" /> <Key - latin:keyLabel="w" - latin:moreKeys="@string/more_keys_for_w" /> + latin:keyLabel="w" /> <Key latin:keyLabel="e" latin:moreKeys="@string/more_keys_for_e" /> @@ -58,15 +56,14 @@ latin:keyLabel="o" latin:moreKeys="@string/more_keys_for_o" /> <Key - latin:keyLabel="p" - latin:moreKeys="@string/more_keys_for_p" /> + latin:keyLabel="p" /> <Key latin:keyStyle="deleteKeyStyle" latin:keyXPos="-9.219%p" latin:keyWidth="fillBoth" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row2" /> + latin:keyboardLayout="@xml/row_qwerty2" /> <Row latin:keyWidth="8.047%p" > @@ -91,33 +88,13 @@ latin:moreKeys="@string/more_keys_for_n" /> <Key latin:keyLabel="m" /> - <switch> - <case - latin:mode="email" - > - <Key - latin:keyLabel="," /> - <Key - latin:keyLabel="." /> - </case> - <default> - <Key - latin:keyLabel="," - latin:keyLabelOption="hasUppercaseLetter" - latin:keyHintLabel="!" - latin:moreKeys="!" /> - <Key - latin:keyLabel="." - latin:keyLabelOption="hasUppercaseLetter" - latin:keyHintLabel="\?" - latin:moreKeys="\?" /> - </default> - </switch> + <include + latin:keyboardLayout="@xml/keys_comma_period" /> <Key latin:keyStyle="shiftKeyStyle" latin:keyXPos="-13.750%p" latin:keyWidth="fillBoth" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml-sw768dp/kbd_rows_scandinavian.xml b/java/res/xml-sw768dp/rows_scandinavian.xml index b9d168036..437316699 100644 --- a/java/res/xml-sw768dp/kbd_rows_scandinavian.xml +++ b/java/res/xml-sw768dp/rows_scandinavian.xml @@ -22,20 +22,18 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="7.375%p" > <Key latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="7.500%p" /> <Key - latin:keyLabel="q" - latin:moreKeys="@string/more_keys_for_q" /> + latin:keyLabel="q" /> <Key - latin:keyLabel="w" - latin:moreKeys="@string/more_keys_for_w" /> + latin:keyLabel="w" /> <Key latin:keyLabel="e" latin:moreKeys="@string/more_keys_for_e" /> @@ -58,10 +56,9 @@ latin:keyLabel="o" latin:moreKeys="@string/more_keys_for_o" /> <Key - latin:keyLabel="p" - latin:moreKeys="@string/more_keys_for_p" /> + latin:keyLabel="p" /> <Key - latin:keyLabel="å" /> + latin:keyLabel="@string/keylabel_for_scandinavia_row1_11" /> <Key latin:keyStyle="deleteKeyStyle" latin:keyXPos="-11.500%p" @@ -72,7 +69,7 @@ > <Key latin:keyStyle="toSymbolKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="9.375%p" /> <Key latin:keyLabel="a" @@ -105,7 +102,7 @@ latin:keyLabel="@string/keylabel_for_scandinavia_row2_11" latin:moreKeys="@string/more_keys_for_scandinavia_row2_11" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-9.375%p" latin:keyWidth="fillBoth" /> </Row> @@ -134,12 +131,12 @@ <Key latin:keyLabel="m" /> <include - latin:keyboardLayout="@xml/kbd_row3_comma_period" /> + latin:keyboardLayout="@xml/keys_comma_period" /> <Key latin:keyStyle="shiftKeyStyle" latin:keyXPos="-12.750%p" latin:keyWidth="fillRight" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml-sw768dp/kbd_rows_serbian.xml b/java/res/xml-sw768dp/rows_serbian.xml index c07176ef6..665975583 100644 --- a/java/res/xml-sw768dp/kbd_rows_serbian.xml +++ b/java/res/xml-sw768dp/rows_serbian.xml @@ -22,13 +22,13 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="7.125%p" > <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="а" /> @@ -112,12 +112,12 @@ <Key latin:keyLabel="м" /> <include - latin:keyboardLayout="@xml/kbd_row3_comma_period" /> + latin:keyboardLayout="@xml/keys_comma_period" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-13.750%p" latin:keyWidth="fillRight" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml-sw768dp/rows_slavic.xml b/java/res/xml-sw768dp/rows_slavic.xml new file mode 100644 index 000000000..58d5a75fc --- /dev/null +++ b/java/res/xml-sw768dp/rows_slavic.xml @@ -0,0 +1,131 @@ +<?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/key_styles_common" /> + <Row + latin:keyWidth="7.125%p" + > + <Key + latin:keyStyle="tabKeyStyle" + latin:keyLabelFlags="alignLeft" /> + <Key + latin:keyLabel="й" /> + <Key + latin:keyLabel="ц" /> + <Key + latin:keyLabel="у" + latin:moreKeys="@string/more_keys_for_slavic_u" /> + <Key + latin:keyLabel="к" /> + <Key + latin:keyLabel="е" + latin:moreKeys="@string/more_keys_for_slavic_ye" /> + <Key + latin:keyLabel="н" + latin:moreKeys="@string/more_keys_for_slavic_en" /> + <Key + latin:keyLabel="г" /> + <Key + latin:keyLabel="ш" /> + <Key + latin:keyLabel="@string/keylabel_for_slavic_shcha" /> + <Key + latin:keyLabel="з" /> + <Key + latin:keyLabel="х" /> + <Key + latin:keyLabel="ъ" /> + <Key + latin:keyStyle="deleteKeyStyle" + latin:keyWidth="fillBoth" /> + </Row> + <Row + latin:keyWidth="7.125%p" + > + <Key + latin:keyStyle="toSymbolKeyStyle" + latin:keyLabelFlags="alignLeft" + latin:keyWidth="9.375%p" /> + <Key + latin:keyLabel="ф" /> + <Key + latin:keyLabel="@string/keylabel_for_slavic_yery" + latin:moreKeys="@string/more_keys_for_slavic_yery" /> + <Key + latin:keyLabel="в" /> + <Key + latin:keyLabel="а" /> + <Key + latin:keyLabel="п" /> + <Key + latin:keyLabel="р" /> + <Key + latin:keyLabel="о" + latin:moreKeys="@string/more_keys_for_slavic_o" /> + <Key + latin:keyLabel="л" /> + <Key + latin:keyLabel="д" /> + <Key + latin:keyLabel="ж" /> + <Key + latin:keyLabel="э" /> + <Key + latin:keyStyle="enterKeyStyle" + latin:keyXPos="-9.375%p" + latin:keyWidth="fillBoth" /> + </Row> + <Row + latin:keyWidth="7.125%p" + > + <Key + latin:keyStyle="shiftKeyStyle" + latin:keyWidth="12.750%p" /> + <Key + latin:keyLabel="я" /> + <Key + latin:keyLabel="ч" /> + <Key + latin:keyLabel="с" /> + <Key + latin:keyLabel="м" /> + <Key + latin:keyLabel="@string/keylabel_for_slavic_i" /> + <Key + latin:keyLabel="т" /> + <Key + latin:keyLabel="ь" /> + <Key + latin:keyLabel="б" /> + <Key + latin:keyLabel="ю" /> + <include + latin:keyboardLayout="@xml/keys_comma_period" /> + <Key + latin:keyStyle="shiftKeyStyle" + latin:keyWidth="fillBoth" /> + </Row> + <include + latin:keyboardLayout="@xml/row_qwerty4" /> +</merge> diff --git a/java/res/xml-sw768dp/kbd_rows_spanish.xml b/java/res/xml-sw768dp/rows_spanish.xml index c737f400a..864c435a2 100644 --- a/java/res/xml-sw768dp/kbd_rows_spanish.xml +++ b/java/res/xml-sw768dp/rows_spanish.xml @@ -22,15 +22,15 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_row1" /> + latin:keyboardLayout="@xml/row_qwerty1" /> <Row latin:keyWidth="8.125%p" > <Key latin:keyStyle="toSymbolKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="10.167%p" /> <Key latin:keyLabel="a" @@ -59,12 +59,12 @@ <Key latin:keyLabel="ñ" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-15.704%p" latin:keyWidth="fillBoth" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row3" /> + latin:keyboardLayout="@xml/row_qwerty3" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml-sw768dp/kbd_rows_symbols.xml b/java/res/xml-sw768dp/rows_symbols.xml index 987b10cdc..c199ae404 100644 --- a/java/res/xml-sw768dp/kbd_rows_symbols.xml +++ b/java/res/xml-sw768dp/rows_symbols.xml @@ -22,45 +22,55 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <include - latin:keyboardLayout="@xml/kbd_currency_key_styles" /> + latin:keyboardLayout="@xml/key_styles_currency" /> <Row latin:keyWidth="8.282%p" > <Key latin:keyStyle="tabKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="7.969%p" /> <Key latin:keyLabel="@string/keylabel_for_symbols_1" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_1" latin:moreKeys="@string/more_keys_for_symbols_1" /> <Key latin:keyLabel="@string/keylabel_for_symbols_2" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_2" latin:moreKeys="@string/more_keys_for_symbols_2" /> <Key latin:keyLabel="@string/keylabel_for_symbols_3" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_3" latin:moreKeys="@string/more_keys_for_symbols_3" /> <Key latin:keyLabel="@string/keylabel_for_symbols_4" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_4" latin:moreKeys="@string/more_keys_for_symbols_4" /> <Key latin:keyLabel="@string/keylabel_for_symbols_5" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_5" latin:moreKeys="@string/more_keys_for_symbols_5" /> <Key latin:keyLabel="@string/keylabel_for_symbols_6" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_6" latin:moreKeys="@string/more_keys_for_symbols_6" /> <Key latin:keyLabel="@string/keylabel_for_symbols_7" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_7" latin:moreKeys="@string/more_keys_for_symbols_7" /> <Key latin:keyLabel="@string/keylabel_for_symbols_8" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_8" latin:moreKeys="@string/more_keys_for_symbols_8" /> <Key latin:keyLabel="@string/keylabel_for_symbols_9" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_9" latin:moreKeys="@string/more_keys_for_symbols_9" /> <Key latin:keyLabel="@string/keylabel_for_symbols_0" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_0" latin:moreKeys="@string/more_keys_for_symbols_0" /> <Key latin:keyStyle="deleteKeyStyle" @@ -72,7 +82,7 @@ > <Key latin:keyStyle="toAlphaKeyStyle" - latin:keyLabelOption="alignLeft" + latin:keyLabelFlags="alignLeft" latin:keyWidth="11.172%p" /> <Key latin:keyLabel="#" /> @@ -92,14 +102,10 @@ <Key latin:keyLabel="+" latin:moreKeys="@string/more_keys_for_plus" /> + <include + latin:keyboardLayout="@xml/keys_parentheses" /> <Key - latin:keyLabel="(" - latin:moreKeys="[,{,<" /> - <Key - latin:keyLabel=")" - latin:moreKeys="],},>" /> - <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-15.704%p" latin:keyWidth="fillBoth" /> </Row> @@ -109,12 +115,8 @@ <Key latin:keyStyle="toMoreSymbolKeyStyle" latin:keyWidth="13.829%p" /> - <Key - latin:keyLabel="<" - latin:moreKeys="≤,«,‹" /> - <Key - latin:keyLabel=">" - latin:moreKeys="≥,»,›" /> + <include + latin:keyboardLayout="@xml/keys_less_greater" /> <Key latin:keyLabel="=" latin:moreKeys="≠,≈" /> @@ -123,8 +125,7 @@ latin:mode="url" > <Key - latin:keyLabel="\'" - latin:moreKeys="‘,’,‚,‛" /> + latin:keyLabel="\'" /> </case> <default> <Key @@ -171,11 +172,10 @@ latin:keyStyle="spaceKeyStyle" latin:keyXPos="31.250%p" latin:keyWidth="37.500%p" /> - <!-- Note: DroidSans doesn't have double-high-reversed-quotation '\u201f' glyph. --> - <!-- latin:moreKeys="“,”,„,‟,«,»,‘,’,‚,‛" --> <Key latin:keyLabel=""" - latin:moreKeys="“,”,«,»,‘,’,‚,‛" /> + latin:moreKeys="@string/more_keys_for_tablet_double_quote" + latin:maxMoreKeysColumn="4" /> <Key latin:keyLabel="_" /> <switch> diff --git a/java/res/xml-sw768dp/kbd_rows_symbols_shift.xml b/java/res/xml-sw768dp/rows_symbols_shift.xml index 9a9c3a276..e88f78633 100644 --- a/java/res/xml-sw768dp/kbd_rows_symbols_shift.xml +++ b/java/res/xml-sw768dp/rows_symbols_shift.xml @@ -22,15 +22,15 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <include - latin:keyboardLayout="@xml/kbd_currency_key_styles" /> + latin:keyboardLayout="@xml/key_styles_currency" /> <Row latin:keyWidth="8.282%p" > <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" /> @@ -84,12 +84,10 @@ <Key latin:keyLabel="±" latin:moreKeys="∞" /> + <include + latin:keyboardLayout="@xml/keys_curly_brackets" /> <Key - latin:keyLabel="{" /> - <Key - latin:keyLabel="}" /> - <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyXPos="-15.704%p" latin:keyWidth="fillBoth" /> </Row> @@ -109,10 +107,8 @@ latin:keyLabel="™" /> <Key latin:keyLabel="℅" /> - <Key - latin:keyLabel="[" /> - <Key - latin:keyLabel="]" /> + <include + latin:keyboardLayout="@xml/keys_square_brackets" /> <Key latin:keyLabel="¡" /> <Key diff --git a/java/res/xml-tr/kbd_qwerty.xml b/java/res/xml-tr/kbd_qwerty.xml deleted file mode 100644 index d2c38f60a..000000000 --- a/java/res/xml-tr/kbd_qwerty.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?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:keyboardLocale="tr" -> - <include - latin:keyboardLayout="@xml/kbd_rows_qwerty" /> -</Keyboard> diff --git a/java/res/xml-tr/keyboard_set.xml b/java/res/xml-tr/keyboard_set.xml new file mode 100644 index 000000000..da79758ec --- /dev/null +++ b/java/res/xml-tr/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="tr"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_qwerty" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-uk/keyboard_set.xml b/java/res/xml-uk/keyboard_set.xml new file mode 100644 index 000000000..8eb9eccb7 --- /dev/null +++ b/java/res/xml-uk/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="uk"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_slavic" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-vi/keyboard_set.xml b/java/res/xml-vi/keyboard_set.xml new file mode 100644 index 000000000..6d38eb1b4 --- /dev/null +++ b/java/res/xml-vi/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="vi"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_qwerty" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-de-rZZ/kbd_qwerty.xml b/java/res/xml/kbd_arabic.xml index d5fd8ef7a..ce5f30b2f 100644 --- a/java/res/xml-de-rZZ/kbd_qwerty.xml +++ b/java/res/xml/kbd_arabic.xml @@ -20,8 +20,7 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyboardLocale="de" > <include - latin:keyboardLayout="@xml/kbd_rows_qwerty" /> + latin:keyboardLayout="@xml/rows_arabic" /> </Keyboard> diff --git a/java/res/xml-pl/kbd_qwerty.xml b/java/res/xml/kbd_azerty.xml index 44312c52c..7bafe5bca 100644 --- a/java/res/xml-pl/kbd_qwerty.xml +++ b/java/res/xml/kbd_azerty.xml @@ -20,8 +20,7 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyboardLocale="pl" > <include - latin:keyboardLayout="@xml/kbd_rows_qwerty" /> + latin:keyboardLayout="@xml/rows_azerty" /> </Keyboard> diff --git a/java/res/xml-fr/kbd_qwerty.xml b/java/res/xml/kbd_bulgarian.xml index 8c730a24f..a651991c0 100644 --- a/java/res/xml-fr/kbd_qwerty.xml +++ b/java/res/xml/kbd_bulgarian.xml @@ -2,9 +2,9 @@ <!-- /* ** -** Copyright 2008, The Android Open Source Project +** Copyright 2012, The Android Open Source Project ** -** Licensed under the Apache License, Version 2.0 (the "License"); +** Licensed under the Apache License, Version 2.0 (the "License"): ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** @@ -20,8 +20,7 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyboardLocale="fr" > <include - latin:keyboardLayout="@xml/kbd_rows_azerty" /> + latin:keyboardLayout="@xml/rows_bulgarian" /> </Keyboard> diff --git a/java/res/xml-hu/kbd_qwerty.xml b/java/res/xml/kbd_hebrew.xml index 3195d5b1f..74836f342 100644 --- a/java/res/xml-hu/kbd_qwerty.xml +++ b/java/res/xml/kbd_hebrew.xml @@ -20,8 +20,7 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyboardLocale="hu" > <include - latin:keyboardLayout="@xml/kbd_rows_qwertz" /> + latin:keyboardLayout="@xml/rows_hebrew" /> </Keyboard> diff --git a/java/res/xml/kbd_mini_keyboard_template.xml b/java/res/xml/kbd_more_keys_keyboard_template.xml index ad6cf51fe..8e977c5ad 100644 --- a/java/res/xml/kbd_mini_keyboard_template.xml +++ b/java/res/xml/kbd_more_keys_keyboard_template.xml @@ -21,6 +21,6 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" latin:keyWidth="10%p" latin:rowHeight="@dimen/popup_key_height" - style="?attr/miniKeyboardStyle" + style="?attr/moreKeysKeyboardStyle" > </Keyboard> diff --git a/java/res/xml/kbd_number.xml b/java/res/xml/kbd_number.xml index 38dd6bf62..8b0deea97 100644 --- a/java/res/xml/kbd_number.xml +++ b/java/res/xml/kbd_number.xml @@ -23,5 +23,5 @@ latin:keyWidth="26.67%p" > <include - latin:keyboardLayout="@xml/kbd_rows_number" /> + latin:keyboardLayout="@xml/rows_number" /> </Keyboard> diff --git a/java/res/xml/kbd_phone.xml b/java/res/xml/kbd_phone.xml index b550f17c5..91637b62c 100644 --- a/java/res/xml/kbd_phone.xml +++ b/java/res/xml/kbd_phone.xml @@ -23,5 +23,5 @@ latin:keyWidth="26.67%p" > <include - latin:keyboardLayout="@xml/kbd_rows_phone" /> + latin:keyboardLayout="@xml/rows_phone" /> </Keyboard> diff --git a/java/res/xml/kbd_phone_shift.xml b/java/res/xml/kbd_phone_symbols.xml index eea823fc0..7f59a855a 100644 --- a/java/res/xml/kbd_phone_shift.xml +++ b/java/res/xml/kbd_phone_symbols.xml @@ -23,5 +23,5 @@ latin:keyWidth="26.67%p" > <include - latin:keyboardLayout="@xml/kbd_rows_phone_shift" /> + latin:keyboardLayout="@xml/rows_phone_symbols" /> </Keyboard> diff --git a/java/res/xml/kbd_qwerty.xml b/java/res/xml/kbd_qwerty.xml index 40917b921..2f49b943a 100644 --- a/java/res/xml/kbd_qwerty.xml +++ b/java/res/xml/kbd_qwerty.xml @@ -20,8 +20,7 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyboardLocale="en_GB,en_US" > <include - latin:keyboardLayout="@xml/kbd_rows_qwerty" /> + latin:keyboardLayout="@xml/rows_qwerty" /> </Keyboard> diff --git a/java/res/xml-cs/kbd_qwerty.xml b/java/res/xml/kbd_qwertz.xml index 9991ea2d2..9f7e9019c 100644 --- a/java/res/xml-cs/kbd_qwerty.xml +++ b/java/res/xml/kbd_qwertz.xml @@ -20,8 +20,7 @@ <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" - latin:keyboardLocale="cs" > <include - latin:keyboardLayout="@xml/kbd_rows_qwertz" /> + latin:keyboardLayout="@xml/rows_qwertz" /> </Keyboard> diff --git a/java/res/xml/kbd_rows_number.xml b/java/res/xml/kbd_rows_number.xml deleted file mode 100644 index 90ac5686b..000000000 --- a/java/res/xml/kbd_rows_number.xml +++ /dev/null @@ -1,132 +0,0 @@ -<?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="num1KeyStyle" /> - <Key - latin:keyStyle="num2KeyStyle" /> - <Key - latin:keyStyle="num3KeyStyle" /> - <Spacer /> - </Row> - <Row> - <Key - latin:keyStyle="num4KeyStyle" /> - <Key - latin:keyStyle="num5KeyStyle" /> - <Key - latin:keyStyle="num6KeyStyle" /> - <Spacer /> - </Row> - <Row> - <Key - latin:keyStyle="num7KeyStyle" /> - <Key - latin:keyStyle="num8KeyStyle" /> - <Key - latin:keyStyle="num9KeyStyle" /> - <Key - latin:keyStyle="deleteKeyStyle" - latin:keyWidth="fillRight" /> - </Row> - <Row> - <Spacer /> - <Key - latin:keyStyle="num0KeyStyle" /> - <Spacer /> - <Key - latin:keyStyle="returnKeyStyle" - latin:keyWidth="fillRight" /> - </Row> - </case> - <!-- latin:passwordInput="false" --> - <default> - <Row> - <Key - latin:keyLabel="1" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyLabel="2" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyLabel="3" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyLabel="-" - latin:keyStyle="numFunctionalKeyStyle" - latin:keyWidth="fillRight" /> - </Row> - <Row> - <Key - latin:keyLabel="4" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyLabel="5" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyLabel="6" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyLabel="," - latin:keyStyle="numFunctionalKeyStyle" - latin:keyWidth="fillRight" /> - </Row> - <Row> - <Key - latin:keyLabel="7" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyLabel="8" - latin:keyStyle="numKeyStyle"/> - <Key - latin:keyLabel="9" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyStyle="deleteKeyStyle" - latin:keyWidth="fillRight" /> - </Row> - <Row> - <Key - latin:keyStyle="numSpaceKeyStyle" /> - <Key - latin:keyLabel="0" - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyLabel="." - latin:keyStyle="numKeyStyle" /> - <Key - latin:keyStyle="returnKeyStyle" - latin:keyWidth="fillRight" /> - </Row> - </default> - </switch> -</merge> diff --git a/java/res/xml/kbd_scandinavian.xml b/java/res/xml/kbd_scandinavian.xml new file mode 100644 index 000000000..46ddfcb8f --- /dev/null +++ b/java/res/xml/kbd_scandinavian.xml @@ -0,0 +1,26 @@ +<?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" +> + <include + latin:keyboardLayout="@xml/rows_scandinavian" /> +</Keyboard> diff --git a/java/res/xml/kbd_serbian.xml b/java/res/xml/kbd_serbian.xml new file mode 100644 index 000000000..05597c4eb --- /dev/null +++ b/java/res/xml/kbd_serbian.xml @@ -0,0 +1,26 @@ +<?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" +> + <include + latin:keyboardLayout="@xml/rows_serbian" /> +</Keyboard> diff --git a/java/res/xml/kbd_slavic.xml b/java/res/xml/kbd_slavic.xml new file mode 100644 index 000000000..ca891c000 --- /dev/null +++ b/java/res/xml/kbd_slavic.xml @@ -0,0 +1,26 @@ +<?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" +> + <include + latin:keyboardLayout="@xml/rows_slavic" /> +</Keyboard> diff --git a/java/res/xml/kbd_spanish.xml b/java/res/xml/kbd_spanish.xml new file mode 100644 index 000000000..6ce2b5d24 --- /dev/null +++ b/java/res/xml/kbd_spanish.xml @@ -0,0 +1,26 @@ +<?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" +> + <include + latin:keyboardLayout="@xml/rows_spanish" /> +</Keyboard> diff --git a/java/res/xml/kbd_symbols.xml b/java/res/xml/kbd_symbols.xml index 737f684a7..f6612a2f7 100644 --- a/java/res/xml/kbd_symbols.xml +++ b/java/res/xml/kbd_symbols.xml @@ -22,5 +22,5 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_rows_symbols" /> + latin:keyboardLayout="@xml/rows_symbols" /> </Keyboard> diff --git a/java/res/xml/kbd_symbols_shift.xml b/java/res/xml/kbd_symbols_shift.xml index 9c163d694..41a5571ef 100644 --- a/java/res/xml/kbd_symbols_shift.xml +++ b/java/res/xml/kbd_symbols_shift.xml @@ -22,5 +22,5 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_rows_symbols_shift" /> + latin:keyboardLayout="@xml/rows_symbols_shift" /> </Keyboard> diff --git a/java/res/xml/kbd_qwerty_f1.xml b/java/res/xml/key_f1.xml index 83b6ecc8d..83b6ecc8d 100644 --- a/java/res/xml/kbd_qwerty_f1.xml +++ b/java/res/xml/key_f1.xml diff --git a/java/res/xml/kbd_settings_or_tab.xml b/java/res/xml/key_settings_or_tab.xml index 4a8bcc7a6..2d35e3b4a 100644 --- a/java/res/xml/kbd_settings_or_tab.xml +++ b/java/res/xml/key_settings_or_tab.xml @@ -25,8 +25,11 @@ <case latin:hasSettingsKey="true" > + <!-- Because this settings key is not adjacent to the space key, this key should be + just ignored while typing (altCode=CODE_UNSPECIFIED). --> <Key latin:keyStyle="settingsKeyStyle" + latin:altCode="@integer/key_unspecified" latin:keyWidth="9.2%p" /> </case> <!-- hasSettingsKey="false" --> diff --git a/java/res/xml/kbd_key_styles.xml b/java/res/xml/key_styles_common.xml index 453b05dff..0e31bcb31 100644 --- a/java/res/xml/kbd_key_styles.xml +++ b/java/res/xml/key_styles_common.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,109 +56,70 @@ <default> <key-style latin:styleName="f1PopupStyle" - latin:keyLabelOption="hasPopupHint" + latin:keyLabelFlags="hasPopupHint" latin:moreKeys="@string/more_keys_for_f1" latin:backgroundType="functional" /> </default> </switch> <!-- Functional key styles --> - <key-style - latin:styleName="shiftKeyStyle" - latin:code="@integer/key_shift" - latin:keyIcon="iconShiftKey" - latin:keyIconShifted="iconShiftedShiftKey" - latin:backgroundType="sticky" /> - <key-style - latin:styleName="deleteKeyStyle" - latin:code="@integer/key_delete" - latin:keyIcon="iconDeleteKey" - latin:backgroundType="functional" - latin:isRepeatable="true" /> - <!-- Return key style --> <switch> <case - latin:mode="im" - > - <!-- Smiley key. --> - <key-style - latin:styleName="returnKeyStyle" - latin:keyLabel=":-)" - latin:keyOutputText=":-) " - latin:keyLabelOption="hasPopupHint" - latin:moreKeys="@string/more_keys_for_smiley" - latin:maxMoreKeysColumn="5" - latin:backgroundType="functional" /> - </case> - <case - latin:imeAction="actionGo" - > - <key-style - latin:styleName="returnKeyStyle" - latin:code="@integer/key_return" - latin:keyLabel="@string/label_go_key" - latin:keyLabelOption="autoXScale" - latin:backgroundType="action" /> - </case> - <case - latin:imeAction="actionNext" + latin:keyboardSetElement="alphabetManualShifted|alphabetAutomaticShifted" > <key-style - latin:styleName="returnKeyStyle" - latin:code="@integer/key_return" - latin:keyLabel="@string/label_next_key" - latin:keyLabelOption="autoXScale" - latin:backgroundType="action" /> + latin:styleName="shiftKeyStyle" + latin:code="@integer/key_shift" + latin:keyIcon="iconShiftKeyShifted" + latin:keyActionFlags="noKeyPreview" + latin:backgroundType="stickyOff" /> </case> <case - latin:imeAction="actionDone" + latin:keyboardSetElement="alphabetShiftLocked|alphabetShiftLockShifted" > <key-style - latin:styleName="returnKeyStyle" - latin:code="@integer/key_return" - latin:keyLabel="@string/label_done_key" - latin:keyLabelOption="autoXScale" - latin:backgroundType="action" /> - </case> - <case - latin:imeAction="actionSend" - > - <key-style - latin:styleName="returnKeyStyle" - latin:code="@integer/key_return" - latin:keyLabel="@string/label_send_key" - latin:keyLabelOption="autoXScale" - latin:backgroundType="action" /> - </case> - <case - latin:imeAction="actionSearch" - > - <key-style - latin:styleName="returnKeyStyle" - latin:code="@integer/key_return" - latin:keyIcon="iconSearchKey" - latin:backgroundType="action" /> + latin:styleName="shiftKeyStyle" + latin:code="@integer/key_shift" + latin:keyIcon="iconShiftKeyShifted" + latin:keyActionFlags="noKeyPreview" + latin:backgroundType="stickyOn" /> </case> <default> <key-style - latin:styleName="returnKeyStyle" - latin:code="@integer/key_return" - latin:keyIcon="iconReturnKey" - latin:backgroundType="functional" /> + latin:styleName="shiftKeyStyle" + latin:code="@integer/key_shift" + latin:keyIcon="iconShiftKey" + latin:keyActionFlags="noKeyPreview" + latin:backgroundType="stickyOff" /> </default> </switch> <key-style + latin:styleName="deleteKeyStyle" + latin:code="@integer/key_delete" + latin:keyIcon="iconDeleteKey" + latin:keyActionFlags="isRepeatable|noKeyPreview" + latin:backgroundType="functional" /> + <include + latin:keyboardLayout="@xml/key_styles_enter_phone" /> + <key-style latin:styleName="spaceKeyStyle" latin:code="@integer/key_space" + latin:keyActionFlags="noKeyPreview|enableLongPress" latin:backgroundType="functional" /> <key-style latin:styleName="shortcutKeyStyle" latin:code="@integer/key_shortcut" latin:keyIcon="iconShortcutKey" + latin:keyIconDisabled="iconDisabledShortcutKey" + latin:keyLabelFlags="preserveCase" + 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 +147,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|preserveCase" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> </case> <default> @@ -194,6 +156,8 @@ latin:styleName="toSymbolKeyStyle" latin:code="@integer/key_switch_alpha_symbol" latin:keyLabel="@string/label_to_symbol_key" + latin:keyLabelFlags="preserveCase" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> </default> </switch> @@ -201,23 +165,29 @@ latin:styleName="toAlphaKeyStyle" latin:code="@integer/key_switch_alpha_symbol" latin:keyLabel="@string/label_to_alpha_key" + latin:keyLabelFlags="preserveCase" + 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:keyLabelFlags="preserveCase" + latin:keyActionFlags="noKeyPreview" latin:backgroundType="functional" /> <key-style latin:styleName="backFromMoreSymbolKeyStyle" latin:code="@integer/key_shift" latin:keyLabel="@string/label_to_symbol_key" + latin:keyLabelFlags="preserveCase" + 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|preserveCase" latin:moreKeys="@string/more_keys_for_punctuation" - latin:maxMoreKeysColumn="@integer/mini_keyboard_column_for_punctuation" + latin:maxMoreKeysColumn="@integer/more_keys_keyboard_column_for_punctuation" latin:backgroundType="functional" /> </merge> diff --git a/java/res/xml/kbd_currency_key_styles.xml b/java/res/xml/key_styles_currency.xml index 225888337..3e4afdfb5 100644 --- a/java/res/xml/kbd_currency_key_styles.xml +++ b/java/res/xml/key_styles_currency.xml @@ -26,7 +26,7 @@ latin:passwordInput="true" > <include - latin:keyboardLayout="@xml/kbd_currency_dollar_key_styles" /> + latin:keyboardLayout="@xml/key_styles_currency_dollar" /> </case> <!-- Countries using Euro currency, 23 countries as for January 2011. --> 1. Andorra (ca_AD, ca_ES) @@ -62,19 +62,19 @@ latin:localeCode="da|de|es|el|fi|fr|it|nl|sk|sl|pt_PT|tr" > <include - latin:keyboardLayout="@xml/kbd_currency_euro_key_styles" /> + latin:keyboardLayout="@xml/key_styles_currency_euro" /> </case> <case latin:languageCode="ca|et|lb|mt|sla" > <include - latin:keyboardLayout="@xml/kbd_currency_euro_key_styles" /> + latin:keyboardLayout="@xml/key_styles_currency_euro" /> </case> <case latin:countryCode="AD|AT|BE|CY|EE|FI|FR|DE|GR|IE|IT|XK|LU|MT|MO|ME|NL|PT|SM|SK|SI|ES|VA" > <include - latin:keyboardLayout="@xml/kbd_currency_euro_key_styles" /> + latin:keyboardLayout="@xml/key_styles_currency_euro" /> </case> <case latin:languageCode="iw" @@ -121,7 +121,7 @@ </case> <default> <include - latin:keyboardLayout="@xml/kbd_currency_dollar_key_styles" /> + latin:keyboardLayout="@xml/key_styles_currency_dollar" /> </default> </switch> </merge> diff --git a/java/res/xml/kbd_currency_dollar_key_styles.xml b/java/res/xml/key_styles_currency_dollar.xml index d5dca2afa..d5dca2afa 100644 --- a/java/res/xml/kbd_currency_dollar_key_styles.xml +++ b/java/res/xml/key_styles_currency_dollar.xml diff --git a/java/res/xml/kbd_currency_euro_key_styles.xml b/java/res/xml/key_styles_currency_euro.xml index 6edddf074..6edddf074 100644 --- a/java/res/xml/kbd_currency_euro_key_styles.xml +++ b/java/res/xml/key_styles_currency_euro.xml diff --git a/java/res/xml/key_styles_enter_phone.xml b/java/res/xml/key_styles_enter_phone.xml new file mode 100644 index 000000000..6af81fb7b --- /dev/null +++ b/java/res/xml/key_styles_enter_phone.xml @@ -0,0 +1,124 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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" +> + <!-- Enter key style --> + <key-style + latin:styleName="defaultEnterKeyStyle" + latin:code="@integer/key_enter" + latin:keyIcon="iconReturnKey" + latin:keyLabelFlags="autoXScale|preserveCase" + latin:keyActionFlags="noKeyPreview" + latin:backgroundType="functional" /> + <key-style + latin:styleName="defaultActionKeyStyle" + latin:code="@integer/key_action_enter" + latin:keyIcon="iconUndefined" + latin:backgroundType="action" + latin:parentStyle="defaultEnterKeyStyle" /> + <switch> + <!-- Shift + Enter in textMultiLine field. --> + <case + latin:isMultiLine="true" + latin:keyboardSetElement="alphabetManualShifted|alphabetShiftLockShifted" + > + <key-style + latin:styleName="enterKeyStyle" + latin:parentStyle="defaultEnterKeyStyle" /> + </case> + <!-- Smiley in textShortMessage field. --> + <case + latin:mode="im" + > + <key-style + latin:styleName="enterKeyStyle" + latin:keyLabel=":-)" + latin:keyOutputText=":-) " + latin:keyLabelFlags="hasPopupHint" + latin:moreKeys="@string/more_keys_for_smiley" + latin:maxMoreKeysColumn="5" + latin:backgroundType="functional" /> + </case> + <case + latin:imeAction="actionGo" + > + <key-style + latin:styleName="enterKeyStyle" + latin:keyLabel="@string/label_go_key" + latin:parentStyle="defaultActionKeyStyle" /> + </case> + <case + latin:imeAction="actionNext" + > + <key-style + latin:styleName="enterKeyStyle" + latin:keyLabel="@string/label_next_key" + latin:parentStyle="defaultActionKeyStyle" /> + </case> + <case + latin:imeAction="actionPrevious" + > + <key-style + latin:styleName="enterKeyStyle" + latin:keyLabel="@string/label_previous_key" + latin:parentStyle="defaultActionKeyStyle" /> + </case> + <case + latin:imeAction="actionDone" + > + <key-style + latin:styleName="enterKeyStyle" + latin:keyLabel="@string/label_done_key" + latin:parentStyle="defaultActionKeyStyle" /> + </case> + <case + latin:imeAction="actionSend" + > + <key-style + latin:styleName="enterKeyStyle" + latin:keyLabel="@string/label_send_key" + latin:parentStyle="defaultActionKeyStyle" /> + </case> + <case + latin:imeAction="actionSearch" + > + <key-style + latin:styleName="enterKeyStyle" + latin:keyIcon="iconSearchKey" + latin:parentStyle="defaultActionKeyStyle" /> + </case> + <case + latin:imeAction="actionCustomLabel" + > + <key-style + latin:styleName="enterKeyStyle" + latin:keyLabelFlags="fromCustomActionLabel" + latin:parentStyle="defaultActionKeyStyle" /> + </case> + <!-- imeAction is either actionNone or actionUnspecified. --> + <default> + <key-style + latin:styleName="enterKeyStyle" + latin:parentStyle="defaultEnterKeyStyle" /> + </default> + </switch> +</merge> diff --git a/java/res/xml/key_styles_enter_tablet.xml b/java/res/xml/key_styles_enter_tablet.xml new file mode 100644 index 000000000..702089181 --- /dev/null +++ b/java/res/xml/key_styles_enter_tablet.xml @@ -0,0 +1,111 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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" +> + <!-- Enter key style --> + <key-style + latin:styleName="defaultEnterKeyStyle" + latin:code="@integer/key_enter" + latin:keyIcon="iconReturnKey" + latin:keyLabelFlags="autoXScale|preserveCase" + latin:keyActionFlags="noKeyPreview" + latin:backgroundType="functional" /> + <key-style + latin:styleName="defaultActionKeyStyle" + latin:code="@integer/key_action_enter" + latin:keyIcon="iconUndefined" + latin:backgroundType="action" + latin:parentStyle="defaultEnterKeyStyle" /> + <switch> + <!-- Shift + Enter in textMultiLine field. --> + <case + latin:isMultiLine="true" + latin:keyboardSetElement="alphabetManualShifted|alphabetShiftLockShifted" + > + <key-style + latin:styleName="enterKeyStyle" + latin:parentStyle="defaultEnterKeyStyle" /> + </case> + <case + latin:imeAction="actionGo" + > + <key-style + latin:styleName="enterKeyStyle" + latin:keyLabel="@string/label_go_key" + latin:parentStyle="defaultActionKeyStyle" /> + </case> + <case + latin:imeAction="actionNext" + > + <key-style + latin:styleName="enterKeyStyle" + latin:keyLabel="@string/label_next_key" + latin:parentStyle="defaultActionKeyStyle" /> + </case> + <case + latin:imeAction="actionPrevious" + > + <key-style + latin:styleName="enterKeyStyle" + latin:keyLabel="@string/label_previous_key" + latin:parentStyle="defaultActionKeyStyle" /> + </case> + <case + latin:imeAction="actionDone" + > + <key-style + latin:styleName="enterKeyStyle" + latin:keyLabel="@string/label_done_key" + latin:parentStyle="defaultActionKeyStyle" /> + </case> + <case + latin:imeAction="actionSend" + > + <key-style + latin:styleName="enterKeyStyle" + latin:keyLabel="@string/label_send_key" + latin:parentStyle="defaultActionKeyStyle" /> + </case> + <case + latin:imeAction="actionSearch" + > + <key-style + latin:styleName="enterKeyStyle" + latin:keyIcon="iconSearchKey" + latin:parentStyle="defaultActionKeyStyle" /> + </case> + <case + latin:imeAction="actionCustomLabel" + > + <key-style + latin:styleName="enterKeyStyle" + latin:keyLabelFlags="fromCustomActionLabel" + latin:parentStyle="defaultActionKeyStyle" /> + </case> + <!-- imeAction is either actionNone or actionUnspecified. --> + <default> + <key-style + latin:styleName="enterKeyStyle" + latin:parentStyle="defaultEnterKeyStyle" /> + </default> + </switch> +</merge> diff --git a/java/res/xml/kbd_numkey_styles.xml b/java/res/xml/key_styles_number.xml index 5d5439906..7307a1a2b 100644 --- a/java/res/xml/kbd_numkey_styles.xml +++ b/java/res/xml/key_styles_number.xml @@ -22,23 +22,30 @@ 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" latin:code="48" latin:keyLabel="0 +" + latin:keyActionFlags="enableLongPress" latin:parentStyle="numberKeyStyle" /> <key-style latin:styleName="num1KeyStyle" @@ -89,18 +96,37 @@ latin:code="42" latin:keyLabel="\uff0a" latin:parentStyle="numKeyStyle" /> + <!-- Only for non-tablet device --> <key-style - latin:styleName="numSwitchToAltKeyStyle" - latin:code="@integer/key_shift" + latin:styleName="numPhoneToSymbolKeyStyle" + latin:code="@integer/key_switch_alpha_symbol" latin:keyLabel="@string/label_to_phone_symbols_key" latin:parentStyle="numModeKeyStyle" /> <key-style - latin:styleName="numSwitchToNumericKeyStyle" - latin:code="@integer/key_shift" + latin:styleName="numPhoneToNumericKeyStyle" + latin:code="@integer/key_switch_alpha_symbol" 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="iconSpaceKeyForNumberLayout" + latin:keyActionFlags="enableLongPress" + latin:parentStyle="numKeyBaseStyle" /> </merge> diff --git a/java/res/xml/kbd_symbols_f1.xml b/java/res/xml/key_symbols_f1.xml index 0dd3d9109..0dd3d9109 100644 --- a/java/res/xml/kbd_symbols_f1.xml +++ b/java/res/xml/key_symbols_f1.xml diff --git a/java/res/xml/keyboard_set.xml b/java/res/xml/keyboard_set.xml new file mode 100644 index 000000000..1398b137c --- /dev/null +++ b/java/res/xml/keyboard_set.xml @@ -0,0 +1,42 @@ +<?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. +*/ +--> + +<KeyboardSet + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyboardLocale="en_GB,en_US"> + <Element + latin:elementName="alphabet" + latin:elementKeyboard="@xml/kbd_qwerty" /> + <Element + latin:elementName="symbols" + latin:elementKeyboard="@xml/kbd_symbols" /> + <Element + latin:elementName="symbolsShifted" + latin:elementKeyboard="@xml/kbd_symbols_shift" /> + <Element + latin:elementName="phone" + latin:elementKeyboard="@xml/kbd_phone" /> + <Element + latin:elementName="phoneSymbols" + latin:elementKeyboard="@xml/kbd_phone_symbols" /> + <Element + latin:elementName="number" + latin:elementKeyboard="@xml/kbd_number" /> +</KeyboardSet> diff --git a/java/res/xml-sw600dp/kbd_row3_comma_period.xml b/java/res/xml/keys_comma_period.xml index b84443078..6db02b61d 100644 --- a/java/res/xml-sw600dp/kbd_row3_comma_period.xml +++ b/java/res/xml/keys_comma_period.xml @@ -2,7 +2,7 @@ <!-- /* ** -** Copyright 2011, The Android Open Source Project +** Copyright 2012, 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. @@ -33,14 +33,14 @@ <default> <Key latin:keyLabel="," - latin:keyLabelOption="hasUppercaseLetter" latin:keyHintLabel="!" - latin:moreKeys="!" /> + latin:moreKeys="!" + latin:keyStyle="hasShiftedLetterHintStyle" /> <Key latin:keyLabel="." - latin:keyLabelOption="hasUppercaseLetter" latin:keyHintLabel="\?" - latin:moreKeys="\?" /> + latin:moreKeys="\?" + latin:keyStyle="hasShiftedLetterHintStyle" /> </default> </switch> </merge> diff --git a/java/res/xml/keys_curly_brackets.xml b/java/res/xml/keys_curly_brackets.xml new file mode 100644 index 000000000..d21a09281 --- /dev/null +++ b/java/res/xml/keys_curly_brackets.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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" +> + <Key + latin:keyLabel="{" + latin:code="@integer/keycode_for_left_curly_bracket" /> + <Key + latin:keyLabel="}" + latin:code="@integer/keycode_for_right_curly_bracket" /> +</merge> diff --git a/java/res/xml/keys_less_greater.xml b/java/res/xml/keys_less_greater.xml new file mode 100644 index 000000000..8961d9ce6 --- /dev/null +++ b/java/res/xml/keys_less_greater.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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" +> + <Key + latin:keyLabel="<" + latin:code="@integer/keycode_for_less_than" + latin:moreKeys="@string/more_keys_for_less_than" /> + <Key + latin:keyLabel=">" + latin:code="@integer/keycode_for_greater_than" + latin:moreKeys="@string/more_keys_for_greater_than" /> +</merge> diff --git a/java/res/xml/keys_parentheses.xml b/java/res/xml/keys_parentheses.xml new file mode 100644 index 000000000..6853bf167 --- /dev/null +++ b/java/res/xml/keys_parentheses.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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" +> + <Key + latin:keyLabel="(" + latin:code="@integer/keycode_for_left_parenthesis" + latin:moreKeys="@string/more_keys_for_left_parenthesis" /> + <Key + latin:keyLabel=")" + latin:code="@integer/keycode_for_right_parenthesis" + latin:moreKeys="@string/more_keys_for_right_parenthesis" /> +</merge> diff --git a/java/res/xml/keys_square_brackets.xml b/java/res/xml/keys_square_brackets.xml new file mode 100644 index 000000000..44387c3bf --- /dev/null +++ b/java/res/xml/keys_square_brackets.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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" +> + <Key + latin:keyLabel="[" + latin:code="@integer/keycode_for_left_square_bracket" /> + <Key + latin:keyLabel="]" + latin:code="@integer/keycode_for_right_square_bracket" /> +</merge> diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml index 6184add4d..650f91b9b 100644 --- a/java/res/xml/method.xml +++ b/java/res/xml/method.xml @@ -20,7 +20,8 @@ <!-- 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, be, bg, cs, da, de, de(QWERTY), es, es_US, et, fi, fr, fr_CA, + fr_CH, hr, hu, it, iw, ky, lt, lv, nb, nl, pl, pt, ro, ru, sk, sl, sr, sv, tr, uk, vi --> <!-- 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.--> @@ -31,7 +32,7 @@ android:label="@string/subtype_en_US" android:imeSubtypeLocale="en_US" android:imeSubtypeMode="keyboard" - android:imeSubtypeExtraValue="TrySuppressingImeSwitcher,AsciiCapable,SupportTouchPositionCorrection" + android:imeSubtypeExtraValue="TrySuppressingImeSwitcher,AsciiCapable,SupportTouchPositionCorrection,EnabledWhenDefaultIsNotAsciiCapable" /> <subtype android:icon="@drawable/ic_subtype_keyboard" android:label="@string/subtype_en_GB" @@ -47,6 +48,18 @@ /> <subtype android:icon="@drawable/ic_subtype_keyboard" android:label="@string/subtype_generic" + android:imeSubtypeLocale="be" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="SupportTouchPositionCorrection" + /> + <subtype android:icon="@drawable/ic_subtype_keyboard" + android:label="@string/subtype_generic" + android:imeSubtypeLocale="bg" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="SupportTouchPositionCorrection" + /> + <subtype android:icon="@drawable/ic_subtype_keyboard" + android:label="@string/subtype_generic" android:imeSubtypeLocale="cs" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection" @@ -64,7 +77,7 @@ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection" /> <subtype android:icon="@drawable/ic_subtype_keyboard" - android:label="@string/subtype_de_qwerty" + android:label="@string/subtype_generic_qwerty" android:imeSubtypeLocale="de" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,KeyboardLocale=de_ZZ,SupportTouchPositionCorrection" @@ -77,6 +90,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 +145,24 @@ /> <subtype android:icon="@drawable/ic_subtype_keyboard" android:label="@string/subtype_generic" + android:imeSubtypeLocale="ky" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="SupportTouchPositionCorrection" + /> + <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" @@ -150,12 +187,30 @@ /> <subtype android:icon="@drawable/ic_subtype_keyboard" android:label="@string/subtype_generic" + android:imeSubtypeLocale="ro" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection" + /> + <subtype android:icon="@drawable/ic_subtype_keyboard" + android:label="@string/subtype_generic" android:imeSubtypeLocale="ru" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="SupportTouchPositionCorrection" /> <subtype android:icon="@drawable/ic_subtype_keyboard" android:label="@string/subtype_generic" + android:imeSubtypeLocale="sk" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection" + /> + <subtype android:icon="@drawable/ic_subtype_keyboard" + android:label="@string/subtype_generic" + android:imeSubtypeLocale="sl" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection" + /> + <subtype android:icon="@drawable/ic_subtype_keyboard" + android:label="@string/subtype_generic" android:imeSubtypeLocale="sr" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="SupportTouchPositionCorrection" @@ -172,4 +227,16 @@ android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection" /> + <subtype android:icon="@drawable/ic_subtype_keyboard" + android:label="@string/subtype_generic" + android:imeSubtypeLocale="uk" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="SupportTouchPositionCorrection" + /> + <subtype android:icon="@drawable/ic_subtype_keyboard" + android:label="@string/subtype_generic" + android:imeSubtypeLocale="vi" + android:imeSubtypeMode="keyboard" + android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection" + /> </input-method> diff --git a/java/res/xml/prefs_for_debug.xml b/java/res/xml/prefs_for_debug.xml index 80613a56f..f38b85f0b 100644 --- a/java/res/xml/prefs_for_debug.xml +++ b/java/res/xml/prefs_for_debug.xml @@ -42,4 +42,10 @@ android:defaultValue="false" /> + <CheckBoxPreference + android:key="force_non_distinct_multitouch" + android:title="@string/prefs_force_non_distinct_multitouch" + android:persistent="true" + android:defaultValue="false" + /> </PreferenceScreen> diff --git a/java/res/xml/kbd_qwerty_row1.xml b/java/res/xml/row_qwerty1.xml index e8e8d1b46..cb1f4d297 100644 --- a/java/res/xml/kbd_qwerty_row1.xml +++ b/java/res/xml/row_qwerty1.xml @@ -27,43 +27,50 @@ <Key latin:keyLabel="q" latin:keyHintLabel="1" - latin:moreKeys="@string/more_keys_for_q" /> + latin:additionalMoreKeys="1" /> <Key latin:keyLabel="w" latin:keyHintLabel="2" - latin:moreKeys="@string/more_keys_for_w" /> + latin:additionalMoreKeys="2" /> <Key latin:keyLabel="e" latin:keyHintLabel="3" + latin:additionalMoreKeys="3" latin:moreKeys="@string/more_keys_for_e" /> <Key latin:keyLabel="r" latin:keyHintLabel="4" + latin:additionalMoreKeys="4" latin:moreKeys="@string/more_keys_for_r" /> <Key latin:keyLabel="t" latin:keyHintLabel="5" + latin:additionalMoreKeys="5" latin:moreKeys="@string/more_keys_for_t" /> <Key latin:keyLabel="y" latin:keyHintLabel="6" + latin:additionalMoreKeys="6" latin:moreKeys="@string/more_keys_for_y" /> <Key latin:keyLabel="u" latin:keyHintLabel="7" + latin:additionalMoreKeys="7" latin:moreKeys="@string/more_keys_for_u" /> <Key latin:keyLabel="i" latin:keyHintLabel="8" + latin:additionalMoreKeys="8" latin:moreKeys="@string/more_keys_for_i" /> <Key latin:keyLabel="o" latin:keyHintLabel="9" + latin:additionalMoreKeys="9" latin:moreKeys="@string/more_keys_for_o" /> <Key latin:keyLabel="p" latin:keyHintLabel="0" - latin:moreKeys="@string/more_keys_for_p" + latin:additionalMoreKeys="0" latin:keyWidth="fillRight" /> </Row> </merge> diff --git a/java/res/xml/kbd_qwerty_row2.xml b/java/res/xml/row_qwerty2.xml index 8986780b7..8986780b7 100644 --- a/java/res/xml/kbd_qwerty_row2.xml +++ b/java/res/xml/row_qwerty2.xml diff --git a/java/res/xml/kbd_qwerty_row3.xml b/java/res/xml/row_qwerty3.xml index c2b45e752..c2b45e752 100644 --- a/java/res/xml/kbd_qwerty_row3.xml +++ b/java/res/xml/row_qwerty3.xml diff --git a/java/res/xml/kbd_qwerty_row4.xml b/java/res/xml/row_qwerty4.xml index eb1e9b8b3..8c20a72dc 100644 --- a/java/res/xml/kbd_qwerty_row4.xml +++ b/java/res/xml/row_qwerty4.xml @@ -33,14 +33,14 @@ latin:keyStyle="toSymbolKeyStyle" latin:keyWidth="15%p" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_f1" /> + latin:keyboardLayout="@xml/key_f1" /> <Key latin:keyStyle="spaceKeyStyle" latin:keyWidth="50%p" /> <Key latin:keyStyle="punctuationKeyStyle" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyWidth="fillRight" /> </case> <!-- hasSettingsKey="true" or navigateAction="true" --> @@ -49,9 +49,9 @@ latin:keyStyle="toSymbolKeyStyle" latin:keyWidth="13.75%p" /> <include - latin:keyboardLayout="@xml/kbd_settings_or_tab" /> + latin:keyboardLayout="@xml/key_settings_or_tab" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_f1" /> + latin:keyboardLayout="@xml/key_f1" /> <Key latin:keyStyle="spaceKeyStyle" latin:keyWidth="35.83%p" /> @@ -59,7 +59,7 @@ latin:keyStyle="punctuationKeyStyle" latin:keyWidth="9.2%p" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyWidth="fillRight" /> </default> </switch> diff --git a/java/res/xml/kbd_symbols_row4.xml b/java/res/xml/row_symbols4.xml index 864cf2b8e..be0c94ffa 100644 --- a/java/res/xml/kbd_symbols_row4.xml +++ b/java/res/xml/row_symbols4.xml @@ -33,14 +33,14 @@ latin:keyStyle="toAlphaKeyStyle" latin:keyWidth="15%p" /> <include - latin:keyboardLayout="@xml/kbd_symbols_f1" /> + latin:keyboardLayout="@xml/key_symbols_f1" /> <Key latin:keyStyle="spaceKeyStyle" latin:keyWidth="50%p" /> <Key latin:keyStyle="punctuationKeyStyle" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyWidth="fillRight" /> </case> <!-- hasSettingsKey="true" or navigateAction="true" --> @@ -49,9 +49,9 @@ latin:keyStyle="toAlphaKeyStyle" latin:keyWidth="13.75%p" /> <include - latin:keyboardLayout="@xml/kbd_settings_or_tab" /> + latin:keyboardLayout="@xml/key_settings_or_tab" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_f1" /> + latin:keyboardLayout="@xml/key_f1" /> <Key latin:keyStyle="spaceKeyStyle" latin:keyWidth="35.83%p" /> @@ -59,7 +59,7 @@ latin:keyStyle="punctuationKeyStyle" latin:keyWidth="9.2%p" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyWidth="fillRight" /> </default> </switch> diff --git a/java/res/xml/kbd_symbols_shift_row4.xml b/java/res/xml/row_symbols_shift4.xml index 89e80e5f7..dd13b7175 100644 --- a/java/res/xml/kbd_symbols_shift_row4.xml +++ b/java/res/xml/row_symbols_shift4.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="„" @@ -45,7 +45,7 @@ latin:keyLabel="…" latin:backgroundType="functional" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyWidth="fillRight" /> </case> <!-- hasSettingsKey="true" or navigateAction="true" --> @@ -54,9 +54,9 @@ latin:keyStyle="toAlphaKeyStyle" latin:keyWidth="13.75%p" /> <include - latin:keyboardLayout="@xml/kbd_settings_or_tab" /> + latin:keyboardLayout="@xml/key_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="„" @@ -70,7 +70,7 @@ latin:keyWidth="9.2%p" latin:backgroundType="functional" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyWidth="fillRight" /> </default> </switch> diff --git a/java/res/xml/kbd_rows_arabic.xml b/java/res/xml/rows_arabic.xml index dd5123e4c..2dcd831c2 100644 --- a/java/res/xml/kbd_rows_arabic.xml +++ b/java/res/xml/rows_arabic.xml @@ -22,7 +22,7 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="10%p" > @@ -30,18 +30,19 @@ <Key latin:keyLabel="ض" latin:keyHintLabel="1" - latin:moreKeys="1,١" /> + latin:additionalMoreKeys="1,١" /> <!-- \u0635: ARABIC LETTER SAD --> <Key latin:keyLabel="ص" latin:keyHintLabel="2" - latin:moreKeys="2,٢" /> + latin:additionalMoreKeys="2,٢" /> <!-- \u0642: ARABIC LETTER QAF \u06a8: ARABIC LETTER QAF WITH THREE DOTS ABOVE --> <Key latin:keyLabel="ق" latin:keyHintLabel="3" - latin:moreKeys="3,٣,\u06a8" /> + latin:additionalMoreKeys="3,٣" + latin:moreKeys="\u06a8" /> <!-- \u0641: ARABIC LETTER FEH \u06a4: ARABIC LETTER VEH \u06a2: ARABIC LETTER FEH WITH DOT MOVED BELOW @@ -49,40 +50,43 @@ <Key latin:keyLabel="ف" latin:keyHintLabel="4" - latin:moreKeys="4,٤,\u06a4,\u06a2,\u06a5" /> + latin:additionalMoreKeys="4,٤" + latin:moreKeys="\u06a4,\u06a2,\u06a5" /> <!-- \u063a: ARABIC LETTER GHAIN --> <Key latin:keyLabel="غ" latin:keyHintLabel="5" - latin:moreKeys="5,٥" /> + latin:additionalMoreKeys="5,٥" /> <!-- \u0639: ARABIC LETTER AIN --> <Key latin:keyLabel="ع" latin:keyHintLabel="6" - latin:moreKeys="6,٦" /> + latin:additionalMoreKeys="6,٦" /> <!-- \u0647: ARABIC LETTER HEH \ufeeb: ARABIC LETTER HEH INITIAL FORM \u0647\u0640: ARABIC LETTER HEH + Zero width joiner --> <Key latin:keyLabel="ه" latin:keyHintLabel="7" - latin:moreKeys="7,٧,\ufeeb|\u0647\u200D" /> + latin:additionalMoreKeys="7,٧" + latin:moreKeys="\ufeeb|\u0647\u200D" /> <!-- \u062e: ARABIC LETTER KHAH --> <Key latin:keyLabel="خ" latin:keyHintLabel="8" - latin:moreKeys="8,٨" /> + latin:additionalMoreKeys="8,٨" /> <!-- \u062d: ARABIC LETTER HAH --> <Key latin:keyLabel="ح" latin:keyHintLabel="9" - latin:moreKeys="9,٩" /> + latin:additionalMoreKeys="9,٩" /> <!-- \u062c: ARABIC LETTER JEEM \u0686: ARABIC LETTER TCHEH --> <Key latin:keyLabel="ج" latin:keyHintLabel="0" - latin:moreKeys="0,٠,\u0686" + latin:additionalMoreKeys="0,٠" + latin:moreKeys="\u0686" latin:keyWidth="fillRight" /> </Row> <Row @@ -185,5 +189,5 @@ latin:visualInsetsLeft="1%p" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml/kbd_rows_azerty.xml b/java/res/xml/rows_azerty.xml index 54fe546e3..533c683d6 100644 --- a/java/res/xml/kbd_rows_azerty.xml +++ b/java/res/xml/rows_azerty.xml @@ -22,58 +22,66 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="10%p" > <Key latin:keyLabel="a" latin:keyHintLabel="1" + latin:additionalMoreKeys="1" latin:moreKeys="@string/more_keys_for_a" /> <Key latin:keyLabel="z" latin:keyHintLabel="2" + latin:additionalMoreKeys="2" latin:moreKeys="@string/more_keys_for_z" /> <Key latin:keyLabel="e" latin:keyHintLabel="3" + latin:additionalMoreKeys="3" latin:moreKeys="@string/more_keys_for_e" /> <Key latin:keyLabel="r" latin:keyHintLabel="4" + latin:additionalMoreKeys="4" latin:moreKeys="@string/more_keys_for_r" /> <Key latin:keyLabel="t" latin:keyHintLabel="5" + latin:additionalMoreKeys="5" latin:moreKeys="@string/more_keys_for_t" /> <Key latin:keyLabel="y" latin:keyHintLabel="6" + latin:additionalMoreKeys="6" latin:moreKeys="@string/more_keys_for_y" /> <Key latin:keyLabel="u" latin:keyHintLabel="7" + latin:additionalMoreKeys="7" latin:moreKeys="@string/more_keys_for_u" /> <Key latin:keyLabel="i" latin:keyHintLabel="8" + latin:additionalMoreKeys="8" latin:moreKeys="@string/more_keys_for_i" /> <Key latin:keyLabel="o" latin:keyHintLabel="9" + latin:additionalMoreKeys="9" latin:moreKeys="@string/more_keys_for_o" /> <Key latin:keyLabel="p" latin:keyHintLabel="0" - latin:moreKeys="@string/more_keys_for_p" + latin:additionalMoreKeys="0" latin:keyWidth="fillRight" /> </Row> <Row latin:keyWidth="10%p" > <Key - latin:keyLabel="q" - latin:moreKeys="@string/more_keys_for_q" /> + latin:keyLabel="q" /> <Key latin:keyLabel="s" latin:moreKeys="@string/more_keys_for_s" /> @@ -107,8 +115,7 @@ latin:keyWidth="15%p" latin:visualInsetsRight="1%p" /> <Key - latin:keyLabel="w" - latin:moreKeys="@string/more_keys_for_w" /> + latin:keyLabel="w" /> <Key latin:keyLabel="x" /> <Key @@ -123,14 +130,18 @@ <Key latin:keyLabel="n" latin:moreKeys="@string/more_keys_for_n" /> + <!-- TODO: Introduce a flag, such as strinctMoreKeysOrder, to control moreKeys display + order more precisely. --> + <!-- This key is close enough to right edge, so that the 4-more keys will be displayed in + order of "4,3,1,2". See @string/more_keys_for_single_quote --> <Key latin:keyLabel="\'" - latin:moreKeys="‘,’,‚,‛" /> + latin:moreKeys="\u2018,\u2019,\u201b,\u201a" /> <Key latin:keyStyle="deleteKeyStyle" latin:keyWidth="fillRight" latin:visualInsetsLeft="1%p" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml/rows_bulgarian.xml b/java/res/xml/rows_bulgarian.xml new file mode 100644 index 000000000..2eac93a7e --- /dev/null +++ b/java/res/xml/rows_bulgarian.xml @@ -0,0 +1,129 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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/key_styles_common" /> + <Row + latin:keyWidth="9.091%p" + > + <Key + latin:keyLabel="ч" + latin:keyHintLabel="1" + latin:additionalMoreKeys="1" /> + <Key + latin:keyLabel="ш" + latin:keyHintLabel="2" + latin:additionalMoreKeys="2" /> + <Key + latin:keyLabel="е" + latin:keyHintLabel="3" + latin:additionalMoreKeys="3" /> + <Key + latin:keyLabel="р" + latin:keyHintLabel="4" + latin:additionalMoreKeys="4" /> + <Key + latin:keyLabel="т" + latin:keyHintLabel="5" + latin:additionalMoreKeys="5" /> + <Key + latin:keyLabel="ъ" + latin:keyHintLabel="6" + latin:additionalMoreKeys="6" /> + <Key + latin:keyLabel="у" + latin:keyHintLabel="7" + latin:additionalMoreKeys="7" /> + <Key + latin:keyLabel="и" + latin:keyHintLabel="8" + latin:additionalMoreKeys="8" + latin:moreKeys="ѝ" /> + <Key + latin:keyLabel="о" + latin:keyHintLabel="9" + latin:additionalMoreKeys="9" /> + <Key + latin:keyLabel="п" + latin:keyHintLabel="0" + latin:additionalMoreKeys="0" /> + <Key + latin:keyLabel="я" + latin:keyWidth="fillRight" /> + </Row> + <Row + latin:keyWidth="9.091%p" + > + <Key + latin:keyLabel="а" /> + <Key + latin:keyLabel="с" /> + <Key + latin:keyLabel="д" /> + <Key + latin:keyLabel="ф" /> + <Key + latin:keyLabel="г" /> + <Key + latin:keyLabel="х" /> + <Key + latin:keyLabel="й" /> + <Key + latin:keyLabel="к" /> + <Key + latin:keyLabel="л" /> + <Key + latin:keyLabel="щ" /> + <Key + latin:keyLabel="ь" + latin:keyWidth="fillRight" /> + </Row> + <Row + latin:keyWidth="9.091%p" + > + <Key + latin:keyStyle="shiftKeyStyle" + latin:keyWidth="13.636%p" /> + <Key + latin:keyLabel="з" /> + <Key + latin:keyLabel="ж" /> + <Key + latin:keyLabel="ц" /> + <Key + latin:keyLabel="в" /> + <Key + latin:keyLabel="б" /> + <Key + latin:keyLabel="н" /> + <Key + latin:keyLabel="м" /> + <Key + latin:keyLabel="ю" /> + <Key + latin:keyStyle="deleteKeyStyle" + latin:keyWidth="fillRight" /> + </Row> + <include + latin:keyboardLayout="@xml/row_qwerty4" /> +</merge> diff --git a/java/res/xml/kbd_rows_hebrew.xml b/java/res/xml/rows_hebrew.xml index 6be8174c5..a64a09dbc 100644 --- a/java/res/xml/kbd_rows_hebrew.xml +++ b/java/res/xml/rows_hebrew.xml @@ -22,7 +22,7 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="10%p" > @@ -105,5 +105,5 @@ <!-- Here is 5%p space --> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml/rows_number.xml b/java/res/xml/rows_number.xml new file mode 100644 index 000000000..8da83be80 --- /dev/null +++ b/java/res/xml/rows_number.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<merge + xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" + latin:keyWidth="26.67%p" +> + <include + latin:keyboardLayout="@xml/key_styles_common" /> + <include + latin:keyboardLayout="@xml/key_styles_number" /> + <switch> + <case + latin:passwordInput="true" + > + <include + latin:keyboardLayout="@xml/rows_number_password" /> + </case> + <default> + <include + latin:keyboardLayout="@xml/rows_number_normal" /> + </default> + </switch> +</merge> diff --git a/java/res/xml/rows_number_normal.xml b/java/res/xml/rows_number_normal.xml new file mode 100644 index 000000000..b581fb5cd --- /dev/null +++ b/java/res/xml/rows_number_normal.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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" +> + <Row> +<Key + latin:keyLabel="1" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyLabel="2" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyLabel="3" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyLabel="-" + latin:keyStyle="numFunctionalKeyStyle" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <Key + latin:keyLabel="4" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyLabel="5" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyLabel="6" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyLabel="," + latin:keyStyle="numFunctionalKeyStyle" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <Key + latin:keyLabel="7" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyLabel="8" + latin:keyStyle="numKeyStyle"/> + <Key + latin:keyLabel="9" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyStyle="deleteKeyStyle" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <Key + latin:keyStyle="numSpaceKeyStyle" /> + <Key + latin:keyLabel="0" + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyLabel="." + latin:keyStyle="numKeyStyle" /> + <Key + latin:keyStyle="enterKeyStyle" + latin:keyWidth="fillRight" /> + </Row> +</merge> diff --git a/java/res/xml/rows_number_password.xml b/java/res/xml/rows_number_password.xml new file mode 100644 index 000000000..e4272ed3f --- /dev/null +++ b/java/res/xml/rows_number_password.xml @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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" +> + <Row> + <Key + latin:keyStyle="num1KeyStyle" /> + <Key + latin:keyStyle="num2KeyStyle" /> + <Key + latin:keyStyle="num3KeyStyle" /> + <Spacer /> + </Row> + <Row> + <Key + latin:keyStyle="num4KeyStyle" /> + <Key + latin:keyStyle="num5KeyStyle" /> + <Key + latin:keyStyle="num6KeyStyle" /> + <Spacer /> + </Row> + <Row> + <Key + latin:keyStyle="num7KeyStyle" /> + <Key + latin:keyStyle="num8KeyStyle" /> + <Key + latin:keyStyle="num9KeyStyle" /> + <Key + latin:keyStyle="deleteKeyStyle" + latin:keyWidth="fillRight" /> + </Row> + <Row> + <Spacer /> + <Key + latin:keyStyle="num0KeyStyle" /> + <Spacer /> + <Key + latin:keyStyle="enterKeyStyle" + latin:keyWidth="fillRight" /> + </Row> +</merge> diff --git a/java/res/xml/kbd_rows_phone.xml b/java/res/xml/rows_phone.xml index 5500a6078..60296d061 100644 --- a/java/res/xml/kbd_rows_phone.xml +++ b/java/res/xml/rows_phone.xml @@ -22,9 +22,9 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <include - latin:keyboardLayout="@xml/kbd_numkey_styles" /> + latin:keyboardLayout="@xml/key_styles_number" /> <Row> <Key latin:keyStyle="num1KeyStyle" /> @@ -62,13 +62,13 @@ </Row> <Row> <Key - latin:keyStyle="numSwitchToAltKeyStyle" /> + latin:keyStyle="numPhoneToSymbolKeyStyle" /> <Key latin:keyStyle="num0KeyStyle" /> <Key latin:keyStyle="numSpaceKeyStyle" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyWidth="fillRight" /> </Row> </merge> diff --git a/java/res/xml/kbd_rows_phone_shift.xml b/java/res/xml/rows_phone_symbols.xml index 3c283d3e6..7841c56e5 100644 --- a/java/res/xml/kbd_rows_phone_shift.xml +++ b/java/res/xml/rows_phone_symbols.xml @@ -22,9 +22,9 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <include - latin:keyboardLayout="@xml/kbd_numkey_styles" /> + latin:keyboardLayout="@xml/key_styles_number" /> <Row> <Key latin:keyLabel="(" @@ -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" /> @@ -74,14 +71,14 @@ </Row> <Row> <Key - latin:keyStyle="numSwitchToNumericKeyStyle" /> + latin:keyStyle="numPhoneToNumericKeyStyle" /> <Key latin:keyLabel="+" latin:keyStyle="numKeyStyle" /> <Key latin:keyStyle="numSpaceKeyStyle" /> <Key - latin:keyStyle="returnKeyStyle" + latin:keyStyle="enterKeyStyle" latin:keyWidth="fillRight" /> </Row> </merge> diff --git a/java/res/xml/kbd_rows_qwerty.xml b/java/res/xml/rows_qwerty.xml index 6237712f6..71be44e31 100644 --- a/java/res/xml/kbd_rows_qwerty.xml +++ b/java/res/xml/rows_qwerty.xml @@ -22,13 +22,13 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_row1" /> + latin:keyboardLayout="@xml/row_qwerty1" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_row2" /> + latin:keyboardLayout="@xml/row_qwerty2" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_row3" /> + latin:keyboardLayout="@xml/row_qwerty3" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml/kbd_rows_qwertz.xml b/java/res/xml/rows_qwertz.xml index 71bb601e6..11fd9332c 100644 --- a/java/res/xml/kbd_rows_qwertz.xml +++ b/java/res/xml/rows_qwertz.xml @@ -22,54 +22,61 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="10%p" > <Key latin:keyLabel="q" latin:keyHintLabel="1" - latin:moreKeys="@string/more_keys_for_q" /> + latin:additionalMoreKeys="1" /> <Key latin:keyLabel="w" latin:keyHintLabel="2" - latin:moreKeys="@string/more_keys_for_w" /> + latin:additionalMoreKeys="2" /> <Key latin:keyLabel="e" latin:keyHintLabel="3" + latin:additionalMoreKeys="3" latin:moreKeys="@string/more_keys_for_e" /> <Key latin:keyLabel="r" latin:keyHintLabel="4" + latin:additionalMoreKeys="4" latin:moreKeys="@string/more_keys_for_r" /> <Key latin:keyLabel="t" latin:keyHintLabel="5" + latin:additionalMoreKeys="5" latin:moreKeys="@string/more_keys_for_t" /> <Key latin:keyLabel="z" latin:keyHintLabel="6" + latin:additionalMoreKeys="6" latin:moreKeys="@string/more_keys_for_z" /> <Key latin:keyLabel="u" latin:keyHintLabel="7" + latin:additionalMoreKeys="7" latin:moreKeys="@string/more_keys_for_u" /> <Key latin:keyLabel="i" latin:keyHintLabel="8" + latin:additionalMoreKeys="8" latin:moreKeys="@string/more_keys_for_i" /> <Key latin:keyLabel="o" latin:keyHintLabel="9" + latin:additionalMoreKeys="9" latin:moreKeys="@string/more_keys_for_o" /> <Key latin:keyLabel="p" latin:keyHintLabel="0" - latin:moreKeys="@string/more_keys_for_p" + latin:additionalMoreKeys="0" latin:keyWidth="fillRight" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row2" /> + latin:keyboardLayout="@xml/row_qwerty2" /> <Row latin:keyWidth="10%p" > @@ -101,5 +108,5 @@ latin:visualInsetsLeft="1%p" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml/kbd_rows_scandinavian.xml b/java/res/xml/rows_scandinavian.xml index 4f138c514..f5ba96c27 100644 --- a/java/res/xml/kbd_rows_scandinavian.xml +++ b/java/res/xml/rows_scandinavian.xml @@ -22,52 +22,59 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="9.091%p" > <Key latin:keyLabel="q" latin:keyHintLabel="1" - latin:moreKeys="@string/more_keys_for_q" /> + latin:additionalMoreKeys="1" /> <Key latin:keyLabel="w" latin:keyHintLabel="2" - latin:moreKeys="@string/more_keys_for_w" /> + latin:additionalMoreKeys="2" /> <Key latin:keyLabel="e" latin:keyHintLabel="3" + latin:additionalMoreKeys="3" latin:moreKeys="@string/more_keys_for_e" /> <Key latin:keyLabel="r" latin:keyHintLabel="4" + latin:additionalMoreKeys="4" latin:moreKeys="@string/more_keys_for_r" /> <Key latin:keyLabel="t" latin:keyHintLabel="5" + latin:additionalMoreKeys="5" latin:moreKeys="@string/more_keys_for_t" /> <Key latin:keyLabel="y" latin:keyHintLabel="6" + latin:additionalMoreKeys="6" latin:moreKeys="@string/more_keys_for_y" /> <Key latin:keyLabel="u" latin:keyHintLabel="7" + latin:additionalMoreKeys="7" latin:moreKeys="@string/more_keys_for_u" /> <Key latin:keyLabel="i" latin:keyHintLabel="8" + latin:additionalMoreKeys="8" latin:moreKeys="@string/more_keys_for_i" /> <Key latin:keyLabel="o" latin:keyHintLabel="9" + latin:additionalMoreKeys="9" latin:moreKeys="@string/more_keys_for_o" /> <Key latin:keyLabel="p" latin:keyHintLabel="0" - latin:moreKeys="@string/more_keys_for_p" /> + latin:additionalMoreKeys="0" /> <Key - latin:keyLabel="å" + latin:keyLabel="@string/keylabel_for_scandinavia_row1_11" latin:keyWidth="fillRight" /> </Row> <Row @@ -75,8 +82,7 @@ > <Key latin:keyLabel="a" - latin:moreKeys="@string/more_keys_for_a" - latin:keyWidth="8.75%p" /> + latin:moreKeys="@string/more_keys_for_a" /> <Key latin:keyLabel="s" latin:moreKeys="@string/more_keys_for_s" /> @@ -107,7 +113,7 @@ latin:keyWidth="fillRight" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row3" /> + latin:keyboardLayout="@xml/row_qwerty3" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml/kbd_rows_serbian.xml b/java/res/xml/rows_serbian.xml index da4d69521..d2203ce9c 100644 --- a/java/res/xml/kbd_rows_serbian.xml +++ b/java/res/xml/rows_serbian.xml @@ -22,50 +22,50 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="9.091%p" > <Key latin:keyLabel="љ" latin:keyHintLabel="1" - latin:moreKeys="1" /> + latin:additionalMoreKeys="1" /> <Key latin:keyLabel="њ" latin:keyHintLabel="2" - latin:moreKeys="2" /> + latin:additionalMoreKeys="2" /> <Key latin:keyLabel="е" latin:keyHintLabel="3" - latin:moreKeys="3" /> + latin:additionalMoreKeys="3" /> <Key latin:keyLabel="р" latin:keyHintLabel="4" - latin:moreKeys="4" /> + latin:additionalMoreKeys="4" /> <Key latin:keyLabel="т" latin:keyHintLabel="5" - latin:moreKeys="5" /> + latin:additionalMoreKeys="5" /> <Key latin:keyLabel="з" latin:keyHintLabel="6" - latin:moreKeys="6" /> + latin:additionalMoreKeys="6" /> <Key latin:keyLabel="у" latin:keyHintLabel="7" - latin:moreKeys="7" /> + latin:additionalMoreKeys="7" /> <Key latin:keyLabel="и" latin:keyHintLabel="8" - latin:moreKeys="8" /> + latin:additionalMoreKeys="8" /> <Key latin:keyLabel="о" latin:keyHintLabel="9" - latin:moreKeys="9" /> + latin:additionalMoreKeys="9" /> <Key latin:keyLabel="п" latin:keyHintLabel="0" - latin:moreKeys="0" /> + latin:additionalMoreKeys="0" /> <Key latin:keyLabel="ш" latin:keyWidth="fillRight" /> @@ -126,5 +126,5 @@ latin:keyWidth="fillRight" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml/kbd_rows_russian.xml b/java/res/xml/rows_slavic.xml index f1794e750..71e442c7c 100644 --- a/java/res/xml/kbd_rows_russian.xml +++ b/java/res/xml/rows_slavic.xml @@ -22,63 +22,66 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <Row latin:keyWidth="9.091%p" > <Key latin:keyLabel="й" latin:keyHintLabel="1" - latin:moreKeys="1" /> + latin:additionalMoreKeys="1" /> <Key latin:keyLabel="ц" latin:keyHintLabel="2" - latin:moreKeys="2" /> + latin:additionalMoreKeys="2" /> <Key latin:keyLabel="у" latin:keyHintLabel="3" - latin:moreKeys="3" /> + latin:additionalMoreKeys="3" + latin:moreKeys="@string/more_keys_for_slavic_u" /> <Key latin:keyLabel="к" latin:keyHintLabel="4" - latin:moreKeys="4" /> + latin:additionalMoreKeys="4" /> <Key latin:keyLabel="е" latin:keyHintLabel="5" - latin:moreKeys="@string/more_keys_for_cyrillic_e" /> + latin:additionalMoreKeys="5" + latin:moreKeys="@string/more_keys_for_slavic_ye" /> <Key latin:keyLabel="н" latin:keyHintLabel="6" - latin:moreKeys="6" /> + latin:additionalMoreKeys="6" + latin:moreKeys="@string/more_keys_for_slavic_en" /> <Key latin:keyLabel="г" latin:keyHintLabel="7" - latin:moreKeys="7" /> + latin:additionalMoreKeys="7" /> <Key latin:keyLabel="ш" latin:keyHintLabel="8" - latin:moreKeys="8" /> + latin:additionalMoreKeys="8" /> <Key - latin:keyLabel="щ" + latin:keyLabel="@string/keylabel_for_slavic_shcha" latin:keyHintLabel="9" - latin:moreKeys="9" /> + latin:additionalMoreKeys="9" /> <Key latin:keyLabel="з" latin:keyHintLabel="0" - latin:moreKeys="0" /> + latin:additionalMoreKeys="0" /> <Key latin:keyLabel="х" - latin:moreKeys="@string/more_keys_for_cyrillic_ha" + latin:moreKeys="@string/more_keys_for_slavic_ha" latin:keyWidth="fillRight" /> </Row> <Row latin:keyWidth="9.091%p" > <Key - latin:keyLabel="ф" - latin:keyWidth="8.75%p" /> + latin:keyLabel="ф" /> <Key - latin:keyLabel="ы" /> + latin:keyLabel="@string/keylabel_for_slavic_yery" + latin:moreKeys="@string/more_keys_for_slavic_yery" /> <Key latin:keyLabel="в" /> <Key @@ -88,7 +91,8 @@ <Key latin:keyLabel="р" /> <Key - latin:keyLabel="о" /> + latin:keyLabel="о" + latin:moreKeys="@string/more_keys_for_slavic_o" /> <Key latin:keyLabel="л" /> <Key @@ -114,12 +118,12 @@ <Key latin:keyLabel="м" /> <Key - latin:keyLabel="и" /> + latin:keyLabel="@string/keylabel_for_slavic_i" /> <Key latin:keyLabel="т" /> <Key latin:keyLabel="ь" - latin:moreKeys="@string/more_keys_for_cyrillic_soft_sign" /> + latin:moreKeys="@string/more_keys_for_slavic_soft_sign" /> <Key latin:keyLabel="б" /> <Key @@ -129,5 +133,5 @@ latin:keyWidth="fillRight" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml/kbd_rows_spanish.xml b/java/res/xml/rows_spanish.xml index 03d631ee0..4b4cb9d1f 100644 --- a/java/res/xml/kbd_rows_spanish.xml +++ b/java/res/xml/rows_spanish.xml @@ -22,9 +22,9 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_row1" /> + latin:keyboardLayout="@xml/row_qwerty1" /> <Row latin:keyWidth="10%p" > @@ -56,7 +56,7 @@ latin:keyLabel="ñ" /> </Row> <include - latin:keyboardLayout="@xml/kbd_qwerty_row3" /> + latin:keyboardLayout="@xml/row_qwerty3" /> <include - latin:keyboardLayout="@xml/kbd_qwerty_row4" /> + latin:keyboardLayout="@xml/row_qwerty4" /> </merge> diff --git a/java/res/xml/kbd_rows_symbols.xml b/java/res/xml/rows_symbols.xml index c5bcb14c3..81a9a4602 100644 --- a/java/res/xml/kbd_rows_symbols.xml +++ b/java/res/xml/rows_symbols.xml @@ -22,41 +22,51 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <include - latin:keyboardLayout="@xml/kbd_currency_key_styles" /> + latin:keyboardLayout="@xml/key_styles_currency" /> <Row latin:keyWidth="10%p" > <Key latin:keyLabel="@string/keylabel_for_symbols_1" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_1" latin:moreKeys="@string/more_keys_for_symbols_1" /> <Key latin:keyLabel="@string/keylabel_for_symbols_2" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_2" latin:moreKeys="@string/more_keys_for_symbols_2" /> <Key latin:keyLabel="@string/keylabel_for_symbols_3" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_3" latin:moreKeys="@string/more_keys_for_symbols_3" /> <Key latin:keyLabel="@string/keylabel_for_symbols_4" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_4" latin:moreKeys="@string/more_keys_for_symbols_4" /> <Key latin:keyLabel="@string/keylabel_for_symbols_5" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_5" latin:moreKeys="@string/more_keys_for_symbols_5" /> <Key latin:keyLabel="@string/keylabel_for_symbols_6" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_6" latin:moreKeys="@string/more_keys_for_symbols_6" /> <Key latin:keyLabel="@string/keylabel_for_symbols_7" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_7" latin:moreKeys="@string/more_keys_for_symbols_7" /> <Key latin:keyLabel="@string/keylabel_for_symbols_8" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_8" latin:moreKeys="@string/more_keys_for_symbols_8" /> <Key latin:keyLabel="@string/keylabel_for_symbols_9" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_9" latin:moreKeys="@string/more_keys_for_symbols_9" /> <Key latin:keyLabel="@string/keylabel_for_symbols_0" + latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_0" latin:moreKeys="@string/more_keys_for_symbols_0" latin:keyWidth="fillRight" /> </Row> @@ -83,13 +93,8 @@ <Key latin:keyLabel="+" latin:moreKeys="@string/more_keys_for_plus" /> - <Key - latin:keyLabel="(" - latin:moreKeys="@string/more_keys_for_left_parenthesis" /> - <Key - latin:keyLabel=")" - latin:moreKeys="@string/more_keys_for_right_parenthesis" - latin:keyWidth="fillRight" /> + <include + latin:keyboardLayout="@xml/keys_parentheses" /> </Row> <Row latin:keyWidth="10%p" @@ -101,15 +106,13 @@ <Key latin:keyLabel="!" latin:moreKeys="¡" /> - <!-- Note: Neither DroidSans nor Roboto have a glyph for ‟ Double high-reversed-9 quotation mark U+201F. --> - <!-- latin:moreKeys="“,”,„,‟,«,»" --> <Key latin:keyLabel=""" - latin:moreKeys="“,”,«,»" - latin:maxMoreKeysColumn="6" /> + latin:moreKeys="@string/more_keys_for_double_quote" + latin:maxMoreKeysColumn="4" /> <Key latin:keyLabel="\'" - latin:moreKeys="‘,’,‚,‛" /> + latin:moreKeys="@string/more_keys_for_single_quote" /> <Key latin:keyLabel=":" /> <Key @@ -126,5 +129,5 @@ latin:visualInsetsLeft="1%p" /> </Row> <include - latin:keyboardLayout="@xml/kbd_symbols_row4" /> + latin:keyboardLayout="@xml/row_symbols4" /> </merge> diff --git a/java/res/xml/kbd_rows_symbols_shift.xml b/java/res/xml/rows_symbols_shift.xml index 91654b04b..828bd0624 100644 --- a/java/res/xml/kbd_rows_symbols_shift.xml +++ b/java/res/xml/rows_symbols_shift.xml @@ -22,9 +22,9 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <include - latin:keyboardLayout="@xml/kbd_key_styles" /> + latin:keyboardLayout="@xml/key_styles_common" /> <include - latin:keyboardLayout="@xml/kbd_currency_key_styles" /> + latin:keyboardLayout="@xml/key_styles_currency" /> <Row latin:keyWidth="10%p" > @@ -46,11 +46,8 @@ latin:keyLabel="÷" /> <Key latin:keyLabel="×" /> - <Key - latin:keyLabel="{" /> - <Key - latin:keyLabel="}" - latin:keyWidth="fillRight" /> + <include + latin:keyboardLayout="@xml/keys_curly_brackets" /> </Row> <Row latin:keyWidth="10%p" @@ -74,11 +71,8 @@ <Key latin:keyLabel="=" latin:moreKeys="≠,≈,∞" /> - <Key - latin:keyLabel="[" /> - <Key - latin:keyLabel="]" - latin:keyWidth="fillRight" /> + <include + latin:keyboardLayout="@xml/keys_square_brackets" /> </Row> <Row latin:keyWidth="10%p" @@ -98,17 +92,13 @@ latin:moreKeys="§" /> <Key latin:keyLabel="\\" /> - <Key - latin:keyLabel="<" - latin:moreKeys="≤,«,‹" /> - <Key - latin:keyLabel=">" - latin:moreKeys="≥,»,›" /> + <include + latin:keyboardLayout="@xml/keys_less_greater" /> <Key latin:keyStyle="deleteKeyStyle" latin:keyWidth="fillRight" latin:visualInsetsLeft="1%p" /> </Row> <include - latin:keyboardLayout="@xml/kbd_symbols_shift_row4" /> + latin:keyboardLayout="@xml/row_symbols_shift4" /> </merge> 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..9caed00c9 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java @@ -17,7 +17,6 @@ package com.android.inputmethod.accessibility; import android.content.Context; -import android.content.SharedPreferences; import android.inputmethodservice.InputMethodService; import android.media.AudioManager; import android.os.SystemClock; @@ -55,15 +54,15 @@ public class AccessibilityUtils { */ private static final boolean ENABLE_ACCESSIBILITY = true; - public static void init(InputMethodService inputMethod, SharedPreferences prefs) { + public static void init(InputMethodService inputMethod) { if (!ENABLE_ACCESSIBILITY) return; // These only need to be initialized if the kill switch is off. - sInstance.initInternal(inputMethod, prefs); - KeyCodeDescriptionMapper.init(inputMethod, prefs); - AccessibleInputMethodServiceProxy.init(inputMethod, prefs); - AccessibleKeyboardViewProxy.init(inputMethod, prefs); + sInstance.initInternal(inputMethod); + KeyCodeDescriptionMapper.init(); + AccessibleInputMethodServiceProxy.init(inputMethod); + AccessibleKeyboardViewProxy.init(inputMethod); } public static AccessibilityUtils getInstance() { @@ -74,7 +73,7 @@ public class AccessibilityUtils { // This class is not publicly instantiable. } - private void initInternal(Context context, SharedPreferences prefs) { + private void initInternal(Context context) { mContext = context; mAccessibilityManager = (AccessibilityManager) context .getSystemService(Context.ACCESSIBILITY_SERVICE); @@ -120,8 +119,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 +136,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 +170,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/AccessibleInputMethodServiceProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java index 4ab9cb898..961176bb8 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java @@ -17,31 +17,15 @@ package com.android.inputmethod.accessibility; import android.content.Context; -import android.content.SharedPreferences; import android.inputmethodservice.InputMethodService; import android.media.AudioManager; -import android.os.Looper; -import android.os.Message; import android.os.Vibrator; -import android.text.TextUtils; import android.view.KeyEvent; -import android.view.inputmethod.ExtractedText; -import android.view.inputmethod.ExtractedTextRequest; - -import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.StaticInnerHandlerWrapper; public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActionListener { private static final AccessibleInputMethodServiceProxy sInstance = new AccessibleInputMethodServiceProxy(); - /* - * Delay for the handler event that's fired when Accessibility is on and the - * user hovers outside of any valid keys. This is used to let the user know - * that if they lift their finger, nothing will be typed. - */ - private static final long DELAY_NO_HOVER_SELECTION = 250; - /** * Duration of the key click vibration in milliseconds. */ @@ -52,38 +36,9 @@ public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActi private InputMethodService mInputMethod; private Vibrator mVibrator; private AudioManager mAudioManager; - private AccessibilityHandler mAccessibilityHandler; - private static class AccessibilityHandler - extends StaticInnerHandlerWrapper<AccessibleInputMethodServiceProxy> { - private static final int MSG_NO_HOVER_SELECTION = 0; - - public AccessibilityHandler(AccessibleInputMethodServiceProxy outerInstance, - Looper looper) { - super(outerInstance, looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_NO_HOVER_SELECTION: - getOuterInstance().notifyNoHoverSelection(); - break; - } - } - - public void postNoHoverSelection() { - removeMessages(MSG_NO_HOVER_SELECTION); - sendEmptyMessageDelayed(MSG_NO_HOVER_SELECTION, DELAY_NO_HOVER_SELECTION); - } - - public void cancelNoHoverSelection() { - removeMessages(MSG_NO_HOVER_SELECTION); - } - } - - public static void init(InputMethodService inputMethod, SharedPreferences prefs) { - sInstance.initInternal(inputMethod, prefs); + public static void init(InputMethodService inputMethod) { + sInstance.initInternal(inputMethod); } public static AccessibleInputMethodServiceProxy getInstance() { @@ -94,30 +49,10 @@ public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActi // Not publicly instantiable. } - private void initInternal(InputMethodService inputMethod, SharedPreferences prefs) { + private void initInternal(InputMethodService inputMethod) { mInputMethod = inputMethod; mVibrator = (Vibrator) inputMethod.getSystemService(Context.VIBRATOR_SERVICE); mAudioManager = (AudioManager) inputMethod.getSystemService(Context.AUDIO_SERVICE); - mAccessibilityHandler = new AccessibilityHandler(this, inputMethod.getMainLooper()); - } - - /** - * If touch exploration is enabled, cancels the event sent by - * {@link AccessibleInputMethodServiceProxy#onHoverExit(int)} because the - * user is currently hovering above a key. - */ - @Override - public void onHoverEnter(int primaryCode) { - mAccessibilityHandler.cancelNoHoverSelection(); - } - - /** - * If touch exploration is enabled, sends a delayed event to notify the user - * that they are not currently hovering above a key. - */ - @Override - public void onHoverExit(int primaryCode) { - mAccessibilityHandler.postNoHoverSelection(); } /** @@ -125,8 +60,6 @@ public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActi */ @Override public void onFlickGesture(int direction) { - final int keyEventCode; - switch (direction) { case FlickGestureDetector.FLICK_LEFT: sendDownUpKeyEvents(KeyEvent.KEYCODE_DPAD_LEFT); @@ -148,27 +81,4 @@ public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActi mAudioManager.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, FX_VOLUME); mInputMethod.sendDownUpKeyEvents(keyCode); } - - /** - * When Accessibility is turned on, notifies the user that they are not - * currently hovering above a key. By default this will speak the currently - * entered text. - */ - private void notifyNoHoverSelection() { - final ExtractedText extracted = mInputMethod.getCurrentInputConnection().getExtractedText( - new ExtractedTextRequest(), 0); - - if (extracted == null) - return; - - final CharSequence text; - - if (TextUtils.isEmpty(extracted.text)) { - text = mInputMethod.getString(R.string.spoken_no_text_entered); - } else { - text = mInputMethod.getString(R.string.spoken_current_text_is, extracted.text); - } - - AccessibilityUtils.getInstance().speak(text); - } } diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardActionListener.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardActionListener.java index c1e92bec8..31d17d09f 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardActionListener.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardActionListener.java @@ -18,24 +18,6 @@ package com.android.inputmethod.accessibility; public interface AccessibleKeyboardActionListener { /** - * Called when the user hovers inside a key. This is sent only when - * Accessibility is turned on. For keys that repeat, this is only called - * once. - * - * @param primaryCode the code of the key that was hovered over - */ - public void onHoverEnter(int primaryCode); - - /** - * Called when the user hovers outside a key. This is sent only when - * Accessibility is turned on. For keys that repeat, this is only called - * once. - * - * @param primaryCode the code of the key that was hovered over - */ - public void onHoverExit(int primaryCode); - - /** * @param direction the direction of the flick gesture, one of * <ul> * <li>{@link FlickGestureDetector#FLICK_UP} diff --git a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java index cef82267f..2294a18a0 100644 --- a/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java +++ b/java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java @@ -17,7 +17,6 @@ package com.android.inputmethod.accessibility; import android.content.Context; -import android.content.SharedPreferences; import android.graphics.Color; import android.graphics.Paint; import android.inputmethodservice.InputMethodService; @@ -29,9 +28,11 @@ 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.Keyboard; +import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.LatinKeyboardView; import com.android.inputmethod.keyboard.PointerTracker; +import com.android.inputmethod.latin.R; public class AccessibleKeyboardViewProxy { private static final String TAG = AccessibleKeyboardViewProxy.class.getSimpleName(); @@ -42,10 +43,10 @@ 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); + public static void init(InputMethodService inputMethod) { + sInstance.initInternal(inputMethod); sInstance.mListener = AccessibleInputMethodServiceProxy.getInstance(); } @@ -61,7 +62,7 @@ public class AccessibleKeyboardViewProxy { // Not publicly instantiable. } - private void initInternal(InputMethodService inputMethod, SharedPreferences prefs) { + private void initInternal(InputMethodService inputMethod) { final Paint paint = new Paint(); paint.setTextAlign(Paint.Align.LEFT); paint.setTextSize(14.0f); @@ -72,8 +73,7 @@ public class AccessibleKeyboardViewProxy { mGestureDetector = new KeyboardFlickGestureDetector(inputMethod); } - public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event, - PointerTracker tracker) { + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { if (mView == null) { Log.e(TAG, "No keyboard view set!"); return false; @@ -81,7 +81,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 +130,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(mLastHoverKey, false); + mLastHoverKey = key; + fireKeyHoverEvent(mLastHoverKey, true); } return true; @@ -144,7 +144,7 @@ public class AccessibleKeyboardViewProxy { return false; } - private void fireKeyHoverEvent(PointerTracker tracker, int keyIndex, boolean entering) { + private void fireKeyHoverEvent(Key key, boolean entering) { if (mListener == null) { Log.e(TAG, "No accessible keyboard action listener set!"); return; @@ -155,19 +155,12 @@ public class AccessibleKeyboardViewProxy { return; } - if (keyIndex == KeyDetector.NOT_A_KEY) - return; - - final Key key = tracker.getKey(keyIndex); - if (key == null) return; if (entering) { - mListener.onHoverEnter(key.mCode); mView.sendAccessibilityEvent(AccessibilityEventCompatUtils.TYPE_VIEW_HOVER_ENTER); } else { - mListener.onHoverExit(key.mCode); mView.sendAccessibilityEvent(AccessibilityEventCompatUtils.TYPE_VIEW_HOVER_EXIT); } } @@ -185,4 +178,71 @@ public class AccessibleKeyboardViewProxy { return true; } } + + /** + * Notifies the user of changes in the keyboard shift state. + */ + public void notifyShiftState() { + final Keyboard keyboard = mView.getKeyboard(); + final KeyboardId keyboardId = keyboard.mId; + final int elementId = keyboardId.mElementId; + final Context context = mView.getContext(); + final CharSequence text; + + switch (elementId) { + case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED: + case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED: + text = context.getText(R.string.spoken_description_shiftmode_locked); + break; + case KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED: + case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED: + case KeyboardId.ELEMENT_SYMBOLS_SHIFTED: + text = context.getText(R.string.spoken_description_shiftmode_on); + break; + default: + text = context.getText(R.string.spoken_description_shiftmode_off); + } + + AccessibilityUtils.getInstance().speak(text); + } + + /** + * Notifies the user of changes in the keyboard symbols state. + */ + public void notifySymbolsState() { + final Keyboard keyboard = mView.getKeyboard(); + final Context context = mView.getContext(); + final KeyboardId keyboardId = keyboard.mId; + final int elementId = keyboardId.mElementId; + final int resId; + + switch (elementId) { + case KeyboardId.ELEMENT_ALPHABET: + case KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED: + case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED: + case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED: + case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED: + resId = R.string.spoken_description_mode_alpha; + break; + case KeyboardId.ELEMENT_SYMBOLS: + case KeyboardId.ELEMENT_SYMBOLS_SHIFTED: + resId = R.string.spoken_description_mode_symbol; + break; + case KeyboardId.ELEMENT_PHONE: + resId = R.string.spoken_description_mode_phone; + break; + case KeyboardId.ELEMENT_PHONE_SYMBOLS: + resId = R.string.spoken_description_mode_phone_shift; + break; + default: + resId = -1; + } + + if (resId < 0) { + return; + } + + final String text = context.getString(resId); + AccessibilityUtils.getInstance().speak(text); + } } diff --git a/java/src/com/android/inputmethod/accessibility/FlickGestureDetector.java b/java/src/com/android/inputmethod/accessibility/FlickGestureDetector.java index 9d99e3131..db12f76ad 100644 --- a/java/src/com/android/inputmethod/accessibility/FlickGestureDetector.java +++ b/java/src/com/android/inputmethod/accessibility/FlickGestureDetector.java @@ -126,7 +126,6 @@ public abstract class FlickGestureDetector { } final float distanceSquare = calculateDistanceSquare(mCachedHoverEnter, event); - final long timeout = event.getEventTime() - mCachedHoverEnter.getEventTime(); switch (event.getAction()) { case MotionEventCompatUtils.ACTION_HOVER_MOVE: diff --git a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java index 7302830d4..f0dba4a02 100644 --- a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java +++ b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java @@ -17,7 +17,6 @@ package com.android.inputmethod.accessibility; import android.content.Context; -import android.content.SharedPreferences; import android.text.TextUtils; import com.android.inputmethod.keyboard.Key; @@ -39,14 +38,8 @@ public class KeyCodeDescriptionMapper { // Map of key codes to spoken description resource IDs private final HashMap<Integer, Integer> mKeyCodeMap; - // Map of shifted key codes to spoken description resource IDs - private final HashMap<Integer, Integer> mShiftedKeyCodeMap; - - // Map of shift-locked key codes to spoken description resource IDs - private final HashMap<Integer, Integer> mShiftLockedKeyCodeMap; - - public static void init(Context context, SharedPreferences prefs) { - sInstance.initInternal(context, prefs); + public static void init() { + sInstance.initInternal(); } public static KeyCodeDescriptionMapper getInstance() { @@ -56,40 +49,15 @@ public class KeyCodeDescriptionMapper { private KeyCodeDescriptionMapper() { mKeyLabelMap = new HashMap<CharSequence, Integer>(); mKeyCodeMap = new HashMap<Integer, Integer>(); - mShiftedKeyCodeMap = new HashMap<Integer, Integer>(); - mShiftLockedKeyCodeMap = new HashMap<Integer, Integer>(); } - private void initInternal(Context context, SharedPreferences prefs) { + private void initInternal() { // Manual label substitutions for key labels with no string resource mKeyLabelMap.put(":-)", R.string.spoken_description_smiley); // Symbols that most TTS engines can't speak - mKeyCodeMap.put((int) '.', R.string.spoken_description_period); - mKeyCodeMap.put((int) ',', R.string.spoken_description_comma); - mKeyCodeMap.put((int) '(', R.string.spoken_description_left_parenthesis); - mKeyCodeMap.put((int) ')', R.string.spoken_description_right_parenthesis); - mKeyCodeMap.put((int) ':', R.string.spoken_description_colon); - mKeyCodeMap.put((int) ';', R.string.spoken_description_semicolon); - mKeyCodeMap.put((int) '!', R.string.spoken_description_exclamation_mark); - mKeyCodeMap.put((int) '?', R.string.spoken_description_question_mark); - mKeyCodeMap.put((int) '\"', R.string.spoken_description_double_quote); - mKeyCodeMap.put((int) '\'', R.string.spoken_description_single_quote); - mKeyCodeMap.put((int) '*', R.string.spoken_description_star); - mKeyCodeMap.put((int) '#', R.string.spoken_description_pound); mKeyCodeMap.put((int) ' ', R.string.spoken_description_space); - // Non-ASCII symbols (must use escape codes!) - mKeyCodeMap.put((int) '\u2022', R.string.spoken_description_dot); - mKeyCodeMap.put((int) '\u221A', R.string.spoken_description_square_root); - mKeyCodeMap.put((int) '\u03C0', R.string.spoken_description_pi); - mKeyCodeMap.put((int) '\u0394', R.string.spoken_description_delta); - mKeyCodeMap.put((int) '\u2122', R.string.spoken_description_trademark); - mKeyCodeMap.put((int) '\u2105', R.string.spoken_description_care_of); - mKeyCodeMap.put((int) '\u2026', R.string.spoken_description_ellipsis); - mKeyCodeMap.put((int) '\u201E', R.string.spoken_description_low_double_quote); - mKeyCodeMap.put((int) '\uFF0A', R.string.spoken_description_star); - // Special non-character codes defined in Keyboard mKeyCodeMap.put(Keyboard.CODE_DELETE, R.string.spoken_description_delete); mKeyCodeMap.put(Keyboard.CODE_ENTER, R.string.spoken_description_return); @@ -98,12 +66,6 @@ public class KeyCodeDescriptionMapper { mKeyCodeMap.put(Keyboard.CODE_SHORTCUT, R.string.spoken_description_mic); mKeyCodeMap.put(Keyboard.CODE_SWITCH_ALPHA_SYMBOL, R.string.spoken_description_to_symbol); mKeyCodeMap.put(Keyboard.CODE_TAB, R.string.spoken_description_tab); - - // Shifted versions of non-character codes defined in Keyboard - mShiftedKeyCodeMap.put(Keyboard.CODE_SHIFT, R.string.spoken_description_shift_shifted); - - // Shift-locked versions of non-character codes defined in Keyboard - mShiftLockedKeyCodeMap.put(Keyboard.CODE_SHIFT, R.string.spoken_description_caps_lock); } /** @@ -127,25 +89,29 @@ public class KeyCodeDescriptionMapper { */ public CharSequence getDescriptionForKey(Context context, Keyboard keyboard, Key key, boolean shouldObscure) { - if (key.mCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { + final int code = key.mCode; + + if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { final CharSequence description = getDescriptionForSwitchAlphaSymbol(context, keyboard); if (description != null) return description; } + if (code == Keyboard.CODE_SHIFT) { + return getDescriptionForShiftKey(context, keyboard); + } + 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_UNSPECIFIED) { return getDescriptionForKeyCode(context, keyboard, key, shouldObscure); } @@ -163,35 +129,66 @@ public class KeyCodeDescriptionMapper { * the key */ private CharSequence getDescriptionForSwitchAlphaSymbol(Context context, Keyboard keyboard) { - final KeyboardId id = keyboard.mId; - - if (id.isAlphabetKeyboard()) { - return context.getString(R.string.spoken_description_to_symbol); - } else if (id.isSymbolsKeyboard()) { - return context.getString(R.string.spoken_description_to_alpha); - } else if (id.isPhoneShiftKeyboard()) { - return context.getString(R.string.spoken_description_to_numeric); - } else if (id.isPhoneKeyboard()) { - return context.getString(R.string.spoken_description_to_symbol); - } else { + final KeyboardId keyboardId = keyboard.mId; + final int elementId = keyboardId.mElementId; + final int resId; + + switch (elementId) { + case KeyboardId.ELEMENT_ALPHABET: + case KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED: + case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED: + case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED: + case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED: + resId = R.string.spoken_description_to_symbol; + break; + case KeyboardId.ELEMENT_SYMBOLS: + case KeyboardId.ELEMENT_SYMBOLS_SHIFTED: + resId = R.string.spoken_description_to_alpha; + break; + case KeyboardId.ELEMENT_PHONE: + resId = R.string.spoken_description_to_symbol; + break; + case KeyboardId.ELEMENT_PHONE_SYMBOLS: + resId = R.string.spoken_description_to_numeric; + break; + default: + resId = -1; + } + + if (resId < 0) { return null; } + + return context.getString(resId); } /** - * Returns the keycode for the specified key given the current keyboard - * state. + * Returns a context-sensitive description of the "Shift" key. * + * @param context The package's context. * @param keyboard The keyboard on which the key resides. - * @param key The key from which to obtain a key code. - * @return the key code for the specified key + * @return A context-sensitive description of the "Shift" key. */ - private int getCorrectKeyCode(Keyboard keyboard, Key key) { - if (keyboard.isManualTemporaryUpperCase() && !TextUtils.isEmpty(key.mHintLabel)) { - return key.mHintLabel.charAt(0); - } else { - return key.mCode; + private CharSequence getDescriptionForShiftKey(Context context, Keyboard keyboard) { + final KeyboardId keyboardId = keyboard.mId; + final int elementId = keyboardId.mElementId; + final int resId; + + switch (elementId) { + case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED: + case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED: + resId = R.string.spoken_description_caps_lock; + break; + case KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED: + case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED: + case KeyboardId.ELEMENT_SYMBOLS_SHIFTED: + resId = R.string.spoken_description_shift_shifted; + break; + default: + resId = R.string.spoken_description_shift; } + + return context.getString(resId); } /** @@ -217,13 +214,7 @@ public class KeyCodeDescriptionMapper { */ private CharSequence getDescriptionForKeyCode(Context context, Keyboard keyboard, Key key, boolean shouldObscure) { - final int code = getCorrectKeyCode(keyboard, key); - - if (keyboard.isShiftLocked() && mShiftLockedKeyCodeMap.containsKey(code)) { - return context.getString(mShiftLockedKeyCodeMap.get(code)); - } else if (keyboard.isShiftedOrShiftLocked() && mShiftedKeyCodeMap.containsKey(code)) { - return context.getString(mShiftedKeyCodeMap.get(code)); - } + final int code = key.mCode; // If the key description should be obscured, now is the time to do it. final boolean isDefinedNonCtrl = Character.isDefined(code) && !Character.isISOControl(code); diff --git a/java/src/com/android/inputmethod/compat/ArraysCompatUtils.java b/java/src/com/android/inputmethod/compat/ArraysCompatUtils.java index f6afbcfe2..011473bef 100644 --- a/java/src/com/android/inputmethod/compat/ArraysCompatUtils.java +++ b/java/src/com/android/inputmethod/compat/ArraysCompatUtils.java @@ -16,10 +16,14 @@ package com.android.inputmethod.compat; +import android.util.Log; + import java.lang.reflect.Method; import java.util.Arrays; public class ArraysCompatUtils { + private static final String TAG = ArraysCompatUtils.class.getSimpleName(); + private static final Method METHOD_Arrays_binarySearch = CompatUtils .getMethod(Arrays.class, "binarySearch", int[].class, int.class, int.class, int.class); @@ -33,8 +37,15 @@ public class ArraysCompatUtils { } } - /* package */ static int compatBinarySearch(int[] array, int startIndex, int endIndex, - int value) { + // TODO: Implement fast binary search + /* package for testing */ + static int compatBinarySearch(int[] array, int startIndex, int endIndex, int value) { + // Output error log because this method has strict performance penalty. + // Note that this method has been called only from spell checker and spell checker exists + // only from IceCreamSandwich and after, so that there is no chance on pre-ICS device to + // invoke this method. + Log.e(TAG, "Invoked expensive binarySearch"); + if (startIndex > endIndex) throw new IllegalArgumentException(); if (startIndex < 0 || endIndex > array.length) throw new ArrayIndexOutOfBoundsException(); diff --git a/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java b/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java index bcdcef7dc..3247997f6 100644 --- a/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java +++ b/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java @@ -26,12 +26,16 @@ public class EditorInfoCompatUtils { EditorInfo.class, "IME_FLAG_NAVIGATE_NEXT"); private static final Field FIELD_IME_FLAG_NAVIGATE_PREVIOUS = CompatUtils.getField( EditorInfo.class, "IME_FLAG_NAVIGATE_PREVIOUS"); + private static final Field FIELD_IME_FLAG_FORCE_ASCII = CompatUtils.getField( + EditorInfo.class, "IME_FLAG_FORCE_ASCII"); private static final Field FIELD_IME_ACTION_PREVIOUS = CompatUtils.getField( EditorInfo.class, "IME_ACTION_PREVIOUS"); private static final Integer OBJ_IME_FLAG_NAVIGATE_NEXT = (Integer) CompatUtils .getFieldValue(null, null, FIELD_IME_FLAG_NAVIGATE_NEXT); private static final Integer OBJ_IME_FLAG_NAVIGATE_PREVIOUS = (Integer) CompatUtils .getFieldValue(null, null, FIELD_IME_FLAG_NAVIGATE_PREVIOUS); + private static final Integer OBJ_IME_FLAG_FORCE_ASCII = (Integer) CompatUtils + .getFieldValue(null, null, FIELD_IME_FLAG_FORCE_ASCII); private static final Integer OBJ_IME_ACTION_PREVIOUS = (Integer) CompatUtils .getFieldValue(null, null, FIELD_IME_ACTION_PREVIOUS); @@ -47,6 +51,12 @@ public class EditorInfoCompatUtils { return (imeOptions & OBJ_IME_FLAG_NAVIGATE_PREVIOUS) != 0; } + public static boolean hasFlagForceAscii(int imeOptions) { + if (OBJ_IME_FLAG_FORCE_ASCII == null) + return false; + return (imeOptions & OBJ_IME_FLAG_FORCE_ASCII) != 0; + } + public static void performEditorActionNext(InputConnection ic) { ic.performEditorAction(EditorInfo.IME_ACTION_NEXT); } @@ -57,46 +67,47 @@ public class EditorInfoCompatUtils { ic.performEditorAction(OBJ_IME_ACTION_PREVIOUS); } - public static String imeOptionsName(int imeOptions) { - if (imeOptions == -1) - return null; + public static String imeActionName(int imeOptions) { final int actionId = imeOptions & EditorInfo.IME_MASK_ACTION; - final String action; switch (actionId) { - case EditorInfo.IME_ACTION_UNSPECIFIED: - action = "actionUnspecified"; - break; - case EditorInfo.IME_ACTION_NONE: - action = "actionNone"; - break; - case EditorInfo.IME_ACTION_GO: - action = "actionGo"; - break; - case EditorInfo.IME_ACTION_SEARCH: - action = "actionSearch"; - break; - case EditorInfo.IME_ACTION_SEND: - action = "actionSend"; - break; - case EditorInfo.IME_ACTION_NEXT: - action = "actionNext"; - break; - case EditorInfo.IME_ACTION_DONE: - action = "actionDone"; - break; - default: { - if (OBJ_IME_ACTION_PREVIOUS != null && actionId == OBJ_IME_ACTION_PREVIOUS) { - action = "actionPrevious"; - } else { - action = "actionUnknown(" + actionId + ")"; - } - break; + case EditorInfo.IME_ACTION_UNSPECIFIED: + return "actionUnspecified"; + case EditorInfo.IME_ACTION_NONE: + return "actionNone"; + case EditorInfo.IME_ACTION_GO: + return "actionGo"; + case EditorInfo.IME_ACTION_SEARCH: + return "actionSearch"; + case EditorInfo.IME_ACTION_SEND: + return "actionSend"; + case EditorInfo.IME_ACTION_NEXT: + return "actionNext"; + case EditorInfo.IME_ACTION_DONE: + return "actionDone"; + default: + if (OBJ_IME_ACTION_PREVIOUS != null && actionId == OBJ_IME_ACTION_PREVIOUS) { + return "actionPrevious"; + } else { + return "actionUnknown(" + actionId + ")"; } } + } + + public static String imeOptionsName(int imeOptions) { + final String action = imeActionName(imeOptions); + final StringBuilder flags = new StringBuilder(); if ((imeOptions & EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) { - return "flagNoEnterAction|" + action; - } else { - return action; + flags.append("flagNoEnterAction|"); + } + if (hasFlagNavigateNext(imeOptions)) { + flags.append("flagNavigateNext|"); + } + if (hasFlagNavigatePrevious(imeOptions)) { + flags.append("flagNavigatePrevious|"); + } + if (hasFlagForceAscii(imeOptions)) { + flags.append("flagForceAscii|"); } + return (action != null) ? flags + action : flags.toString(); } } 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/compat/SuggestionsInfoCompatUtils.java b/java/src/com/android/inputmethod/compat/SuggestionsInfoCompatUtils.java new file mode 100644 index 000000000..6a0d4dd9e --- /dev/null +++ b/java/src/com/android/inputmethod/compat/SuggestionsInfoCompatUtils.java @@ -0,0 +1,43 @@ +/* + * 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.compat; + +import android.view.textservice.SuggestionsInfo; + +import java.lang.reflect.Field; + +public class SuggestionsInfoCompatUtils { + private static final Field FIELD_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = CompatUtils.getField( + SuggestionsInfo.class, "RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS"); + private static final Integer OBJ_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = (Integer) CompatUtils + .getFieldValue(null, null, FIELD_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS);; + private static final int RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = + OBJ_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS != null + ? OBJ_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS : 0; + + private SuggestionsInfoCompatUtils() { + } + + /** + * Returns the flag value of the attributes of the suggestions that can be obtained by + * {@link #getSuggestionsAttributes}: this tells that the text service thinks + * the result suggestions include highly recommended ones. + */ + public static int getValueOf_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS() { + return RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS; + } +} diff --git a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java index 3f8c2ef8f..f632b0e02 100644 --- a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java +++ b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java @@ -16,23 +16,6 @@ package com.android.inputmethod.deprecated; -import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; -import com.android.inputmethod.compat.InputMethodServiceCompatWrapper; -import com.android.inputmethod.compat.SharedPreferencesCompat; -import com.android.inputmethod.deprecated.voice.FieldContext; -import com.android.inputmethod.deprecated.voice.Hints; -import com.android.inputmethod.deprecated.voice.SettingsUtil; -import com.android.inputmethod.deprecated.voice.VoiceInput; -import com.android.inputmethod.keyboard.KeyboardSwitcher; -import com.android.inputmethod.latin.EditingUtils; -import com.android.inputmethod.latin.LatinIME; -import com.android.inputmethod.latin.LatinIME.UIHandler; -import com.android.inputmethod.latin.LatinImeLogger; -import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.SubtypeSwitcher; -import com.android.inputmethod.latin.SuggestedWords; -import com.android.inputmethod.latin.Utils; - import android.app.AlertDialog; import android.content.ContentResolver; import android.content.Context; @@ -63,6 +46,24 @@ import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; import android.widget.TextView; +import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; +import com.android.inputmethod.compat.InputMethodServiceCompatWrapper; +import com.android.inputmethod.compat.SharedPreferencesCompat; +import com.android.inputmethod.deprecated.voice.FieldContext; +import com.android.inputmethod.deprecated.voice.Hints; +import com.android.inputmethod.deprecated.voice.SettingsUtil; +import com.android.inputmethod.deprecated.voice.VoiceInput; +import com.android.inputmethod.keyboard.KeyboardSwitcher; +import com.android.inputmethod.keyboard.LatinKeyboardView; +import com.android.inputmethod.latin.EditingUtils; +import com.android.inputmethod.latin.LatinIME; +import com.android.inputmethod.latin.LatinIME.UIHandler; +import com.android.inputmethod.latin.LatinImeLogger; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.SubtypeSwitcher; +import com.android.inputmethod.latin.SuggestedWords; +import com.android.inputmethod.latin.Utils; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -695,12 +696,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 +710,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 +724,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)); } @@ -747,8 +748,9 @@ public class VoiceProxy implements VoiceInput.UiListener { // keep showing the warning. if (mSubtypeSwitcher.isVoiceMode() && windowToken != null) { // Close keyboard view if it is been shown. - if (KeyboardSwitcher.getInstance().isInputViewShown()) - KeyboardSwitcher.getInstance().getKeyboardView().purgeKeyboardAndClosing(); + final LatinKeyboardView keyboardView = KeyboardSwitcher.getInstance().getKeyboardView(); + if (keyboardView != null && keyboardView.isShown()) + keyboardView.purgeKeyboardAndClosing(); startListening(false, windowToken); } // If we have no token, onAttachedToWindow will take care of showing dialog and start diff --git a/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java b/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java index dbe7aec6a..e75e14861 100644 --- a/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java +++ b/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java @@ -17,7 +17,7 @@ package com.android.inputmethod.deprecated.languageswitcher; import com.android.inputmethod.compat.SharedPreferencesCompat; -import com.android.inputmethod.keyboard.internal.KeyboardBuilder; +import com.android.inputmethod.keyboard.KeyboardSet; import com.android.inputmethod.latin.DictionaryFactory; import com.android.inputmethod.latin.LocaleUtils; import com.android.inputmethod.latin.R; @@ -162,8 +162,8 @@ public class InputLanguageSelection extends PreferenceActivity { try { final String localeStr = locale.toString(); - final String[] layoutCountryCodes = KeyboardBuilder.parseKeyboardLocale( - this, R.xml.kbd_qwerty).split(",", -1); + final String[] layoutCountryCodes = KeyboardSet.parseKeyboardLocale( + getResources(), R.xml.keyboard_set).split(",", -1); if (!TextUtils.isEmpty(localeStr) && layoutCountryCodes.length > 0) { for (String s : layoutCountryCodes) { if (s.equals(localeStr)) { 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..cf3a437cf 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -22,56 +22,64 @@ import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.text.TextUtils; +import android.util.Log; import android.util.Xml; +import com.android.inputmethod.keyboard.internal.KeySpecParser; import com.android.inputmethod.keyboard.internal.KeyStyles; import com.android.inputmethod.keyboard.internal.KeyStyles.KeyStyle; -import com.android.inputmethod.keyboard.internal.KeyboardBuilder; -import com.android.inputmethod.keyboard.internal.KeyboardBuilder.ParseException; import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; -import com.android.inputmethod.keyboard.internal.KeyboardParams; -import com.android.inputmethod.keyboard.internal.MoreKeySpecParser; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.Utils; +import com.android.inputmethod.latin.XmlParseUtils; import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; -import java.util.HashMap; -import java.util.Map; +import java.util.Arrays; /** * Class for describing the position and characteristics of a single key in the keyboard. */ public class Key { + private static final String TAG = Key.class.getSimpleName(); + /** * 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; + public final String 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; + public final String mHintLabel; + /** 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_SHIFTED_LETTER_HINT = 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; + private static final int LABEL_FLAGS_PRESERVE_CASE = 0x8000; + private static final int LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED = 0x10000; + private static final int LABEL_FLAGS_FROM_CUSTOM_ACTION_LABEL = 0x20000; /** Icon to display instead of a label. Icon takes precedence over a label */ - private Drawable mIcon; + private final int mIconId; + /** Icon for disabled state */ + private final int mDisabledIconId; /** Preview version of the icon, for the preview popup */ - private Drawable mPreviewIcon; + private final int mPreviewIconId; /** Width of the key, not including the gap */ public final int mWidth; @@ -94,7 +102,7 @@ public class Key { /** Text to output when pressed. This can be multiple characters, like ".com" */ public final CharSequence mOutputText; /** More keys */ - public final CharSequence[] mMoreKeys; + public final String[] mMoreKeys; /** More keys maximum column number */ public final int mMaxMoreKeysColumn; @@ -103,77 +111,38 @@ public class Key { public static final int BACKGROUND_TYPE_NORMAL = 0; public static final int BACKGROUND_TYPE_FUNCTIONAL = 1; public static final int BACKGROUND_TYPE_ACTION = 2; - public static final int BACKGROUND_TYPE_STICKY = 3; + public static final int BACKGROUND_TYPE_STICKY_OFF = 3; + public static final int BACKGROUND_TYPE_STICKY_ON = 4; + + 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; + private static final int ACTION_FLAGS_ENABLE_LONG_PRESS = 0x08; - /** Whether this key repeats itself when held down */ - public final boolean mRepeatable; + private final int mHashCode; /** The current pressed state of this key */ private boolean mPressed; - /** If this is a sticky key, is its highlight on? */ - private boolean mHighlightOn; /** Key is enabled and responds on press */ private boolean mEnabled = true; - /** Whether this key needs to show the "..." popup hint for special purposes */ - private boolean mNeedsSpecialPopupHint; - - // RTL parenthesis character swapping map. - private static final Map<Integer, Integer> sRtlParenthesisMap = new HashMap<Integer, Integer>(); - - static { - // The all letters need to be mirrored are found at - // http://www.unicode.org/Public/6.0.0/ucd/extracted/DerivedBinaryProperties.txt - addRtlParenthesisPair('(', ')'); - addRtlParenthesisPair('[', ']'); - addRtlParenthesisPair('{', '}'); - addRtlParenthesisPair('<', '>'); - // \u00ab: LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - // \u00bb: RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - addRtlParenthesisPair('\u00ab', '\u00bb'); - // \u2039: SINGLE LEFT-POINTING ANGLE QUOTATION MARK - // \u203a: SINGLE RIGHT-POINTING ANGLE QUOTATION MARK - addRtlParenthesisPair('\u2039', '\u203a'); - // \u2264: LESS-THAN OR EQUAL TO - // \u2265: GREATER-THAN OR EQUAL TO - addRtlParenthesisPair('\u2264', '\u2265'); - } - - private static void addRtlParenthesisPair(int left, int right) { - sRtlParenthesisMap.put(left, right); - sRtlParenthesisMap.put(right, left); - } - - public static int getRtlParenthesisCode(int code, boolean isRtl) { - if (isRtl && sRtlParenthesisMap.containsKey(code)) { - return sRtlParenthesisMap.get(code); - } else { - return code; - } - } - - private static int getCode(Resources res, KeyboardParams params, String moreKeySpec) { - return getRtlParenthesisCode( - MoreKeySpecParser.getCode(res, moreKeySpec), params.mIsRtlKeyboard); - } - - private static Drawable getIcon(KeyboardParams params, String moreKeySpec) { - return params.mIconsSet.getIcon(MoreKeySpecParser.getIconId(moreKeySpec)); - } /** * This constructor is being used only for key in more keys keyboard. */ - public Key(Resources res, KeyboardParams params, String moreKeySpec, + public Key(Resources res, Keyboard.Params params, String moreKeySpec, int x, int y, int width, int height) { - this(params, MoreKeySpecParser.getLabel(moreKeySpec), null, getIcon(params, moreKeySpec), - getCode(res, params, moreKeySpec), MoreKeySpecParser.getOutputText(moreKeySpec), + this(params, KeySpecParser.getLabel(moreKeySpec), null, + KeySpecParser.getIconId(moreKeySpec), + KeySpecParser.getCode(res, moreKeySpec), + KeySpecParser.getOutputText(moreKeySpec), x, y, width, height); } /** * This constructor is being used only for key in popup suggestions pane. */ - public Key(KeyboardParams params, CharSequence label, CharSequence hintLabel, Drawable icon, + public Key(Keyboard.Params params, String label, String hintLabel, int iconId, int code, CharSequence outputText, int x, int y, int width, int height) { mHeight = height - params.mVerticalGap; mHorizontalGap = params.mHorizontalGap; @@ -181,19 +150,24 @@ 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; - mIcon = icon; + mAltCode = Keyboard.CODE_UNSPECIFIED; + mIconId = iconId; + mDisabledIconId = KeyboardIconsSet.ICON_UNDEFINED; + mPreviewIconId = KeyboardIconsSet.ICON_UNDEFINED; // Horizontal gap is divided equally to both sides of the key. mX = x + mHorizontalGap / 2; mY = y; mHitBox.set(x, y, x + width + 1, y + height); + + mHashCode = hashCode(this); } /** @@ -205,9 +179,10 @@ public class Key { * this key. * @param parser the XML parser containing the attributes for this key * @param keyStyles active key styles set + * @throws XmlPullParserException */ - public Key(Resources res, KeyboardParams params, KeyboardBuilder.Row row, - XmlPullParser parser, KeyStyles keyStyles) { + public Key(Resources res, Keyboard.Params params, Keyboard.Builder.Row row, + XmlPullParser parser, KeyStyles keyStyles) throws XmlPullParserException { final float horizontalGap = isSpacer() ? 0 : params.mHorizontalGap; final int keyHeight = row.mRowHeight; mVerticalGap = params.mVerticalGap; @@ -221,9 +196,10 @@ public class Key { String styleName = keyAttr.getString(R.styleable.Keyboard_Key_keyStyle); style = keyStyles.getKeyStyle(styleName); if (style == null) - throw new ParseException("Unknown key style: " + styleName, parser); + throw new XmlParseUtils.ParseException( + "Unknown key style: " + styleName, parser); } else { - style = keyStyles.getEmptyKeyStyle(); + style = KeyStyles.getEmptyKeyStyle(); } final float keyXPos = row.getKeyX(keyAttr); @@ -239,89 +215,238 @@ public class Key { // Update row to have current x coordinate. row.setXPos(keyXPos + keyWidth); - final CharSequence[] moreKeys = style.getTextArray(keyAttr, - R.styleable.Keyboard_Key_moreKeys); - // In Arabic symbol layouts, we'd like to keep digits in more keys regardless of - // config_digit_more_keys_enabled. - if (params.mId.isAlphabetKeyboard() - && !res.getBoolean(R.bool.config_digit_more_keys_enabled)) { - mMoreKeys = MoreKeySpecParser.filterOut(res, moreKeys, MoreKeySpecParser.DIGIT_FILTER); - } else { - mMoreKeys = moreKeys; - } - mMaxMoreKeysColumn = style.getInt(keyAttr, - R.styleable.Keyboard_Key_maxMoreKeysColumn, params.mMaxMiniKeyboardColumn); - 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); - final KeyboardIconsSet iconsSet = params.mIconsSet; - mVisualInsetsLeft = (int) KeyboardBuilder.getDimensionOrFraction(keyAttr, + mVisualInsetsLeft = (int) Keyboard.Builder.getDimensionOrFraction(keyAttr, R.styleable.Keyboard_Key_visualInsetsLeft, params.mBaseWidth, 0); - mVisualInsetsRight = (int) KeyboardBuilder.getDimensionOrFraction(keyAttr, + mVisualInsetsRight = (int) Keyboard.Builder.getDimensionOrFraction(keyAttr, R.styleable.Keyboard_Key_visualInsetsRight, params.mBaseWidth, 0); - mPreviewIcon = iconsSet.getIcon(style.getInt(keyAttr, - R.styleable.Keyboard_Key_keyIconPreview, KeyboardIconsSet.ICON_UNDEFINED)); - mIcon = iconsSet.getIcon(style.getInt(keyAttr, R.styleable.Keyboard_Key_keyIcon, - KeyboardIconsSet.ICON_UNDEFINED)); - final int shiftedIconId = style.getInt(keyAttr, R.styleable.Keyboard_Key_keyIconShifted, - KeyboardIconsSet.ICON_UNDEFINED); - if (shiftedIconId != KeyboardIconsSet.ICON_UNDEFINED) { - final Drawable shiftedIcon = iconsSet.getIcon(shiftedIconId); - params.addShiftedIcon(this, shiftedIcon); + mPreviewIconId = style.getInt(keyAttr, + R.styleable.Keyboard_Key_keyIconPreview, KeyboardIconsSet.ICON_UNDEFINED); + mIconId = style.getInt(keyAttr, + R.styleable.Keyboard_Key_keyIcon, KeyboardIconsSet.ICON_UNDEFINED); + mDisabledIconId = style.getInt(keyAttr, + R.styleable.Keyboard_Key_keyIconDisabled, KeyboardIconsSet.ICON_UNDEFINED); + + mLabelFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags); + final boolean preserveCase = (mLabelFlags & LABEL_FLAGS_PRESERVE_CASE) != 0; + int actionFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyActionFlags); + final String[] additionalMoreKeys = style.getStringArray( + keyAttr, R.styleable.Keyboard_Key_additionalMoreKeys); + final String[] moreKeys = KeySpecParser.insertAddtionalMoreKeys(style.getStringArray( + keyAttr, R.styleable.Keyboard_Key_moreKeys), additionalMoreKeys); + if (moreKeys != null) { + actionFlags |= ACTION_FLAGS_ENABLE_LONG_PRESS; + for (int i = 0; i < moreKeys.length; i++) { + moreKeys[i] = adjustCaseOfStringForKeyboardId( + moreKeys[i], preserveCase, params.mId); + } } - 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); - mOutputText = style.getText(keyAttr, R.styleable.Keyboard_Key_keyOutputText); - // Choose the first letter of the label as primary code if not - // specified. - final int code = style.getInt(keyAttr, R.styleable.Keyboard_Key_code, - Keyboard.CODE_UNSPECIFIED); - if (code == Keyboard.CODE_UNSPECIFIED && !TextUtils.isEmpty(mLabel)) { - final int firstChar = mLabel.charAt(0); - mCode = getRtlParenthesisCode(firstChar, params.mIsRtlKeyboard); - } else if (code != Keyboard.CODE_UNSPECIFIED) { - mCode = code; + mActionFlags = actionFlags; + mMoreKeys = moreKeys; + mMaxMoreKeysColumn = style.getInt(keyAttr, + R.styleable.Keyboard_Key_maxMoreKeysColumn, params.mMaxMoreKeysKeyboardColumn); + + if ((mLabelFlags & LABEL_FLAGS_FROM_CUSTOM_ACTION_LABEL) != 0) { + mLabel = params.mId.mCustomActionLabel; } else { - mCode = Keyboard.CODE_DUMMY; + mLabel = adjustCaseOfStringForKeyboardId(style.getString( + keyAttr, R.styleable.Keyboard_Key_keyLabel), preserveCase, params.mId); } + mHintLabel = adjustCaseOfStringForKeyboardId(style.getString( + keyAttr, R.styleable.Keyboard_Key_keyHintLabel), preserveCase, params.mId); + String outputText = adjustCaseOfStringForKeyboardId(style.getString( + keyAttr, R.styleable.Keyboard_Key_keyOutputText), preserveCase, params.mId); + final int code = style.getInt( + keyAttr, R.styleable.Keyboard_Key_code, Keyboard.CODE_UNSPECIFIED); + // Choose the first letter of the label as primary code if not specified. + if (code == Keyboard.CODE_UNSPECIFIED && TextUtils.isEmpty(outputText) + && !TextUtils.isEmpty(mLabel)) { + if (Utils.codePointCount(mLabel) == 1) { + // Use the first letter of the hint label if shiftedLetterActivated flag is + // specified. + if (hasShiftedLetterHint() && isShiftedLetterActivated() + && !TextUtils.isEmpty(mHintLabel)) { + mCode = mHintLabel.codePointAt(0); + } else { + mCode = mLabel.codePointAt(0); + } + } else { + // In some locale and case, the character might be represented by multiple code + // points, such as upper case Eszett of German alphabet. + outputText = mLabel; + mCode = Keyboard.CODE_OUTPUT_TEXT; + } + } else if (code == Keyboard.CODE_UNSPECIFIED && outputText != null) { + if (Utils.codePointCount(outputText) == 1) { + mCode = outputText.codePointAt(0); + outputText = null; + } else { + mCode = Keyboard.CODE_OUTPUT_TEXT; + } + } else { + mCode = adjustCaseOfCodeForKeyboardId(code, preserveCase, params.mId); + } + mOutputText = outputText; + mAltCode = adjustCaseOfCodeForKeyboardId(style.getInt(keyAttr, + R.styleable.Keyboard_Key_altCode, Keyboard.CODE_UNSPECIFIED), preserveCase, + params.mId); + mHashCode = hashCode(this); keyAttr.recycle(); + + if (hasShiftedLetterHint() && TextUtils.isEmpty(mHintLabel)) { + Log.w(TAG, "hasShiftedLetterHint specified without keyHintLabel: " + this); + } } - public void markAsLeftEdge(KeyboardParams params) { + private static int adjustCaseOfCodeForKeyboardId(int code, boolean preserveCase, + KeyboardId id) { + if (!Keyboard.isLetterCode(code) || preserveCase) return code; + final String text = new String(new int[] { code } , 0, 1); + final String casedText = adjustCaseOfStringForKeyboardId(text, preserveCase, id); + return Utils.codePointCount(casedText) == 1 + ? casedText.codePointAt(0) : Keyboard.CODE_UNSPECIFIED; + } + + private static String adjustCaseOfStringForKeyboardId(String text, boolean preserveCase, + KeyboardId id) { + if (text == null || preserveCase) return text; + switch (id.mElementId) { + case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED: + case KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED: + case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED: + case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED: + return text.toUpperCase(id.mLocale); + default: + return text; + } + } + + private static int hashCode(Key key) { + return Arrays.hashCode(new Object[] { + key.mX, + key.mY, + key.mWidth, + key.mHeight, + key.mCode, + key.mLabel, + key.mHintLabel, + key.mIconId, + key.mBackgroundType, + Arrays.hashCode(key.mMoreKeys), + key.mOutputText, + key.mActionFlags, + key.mLabelFlags, + // Key can be distinguishable without the following members. + // key.mAltCode, + // key.mDisabledIconId, + // key.mPreviewIconId, + // key.mHorizontalGap, + // key.mVerticalGap, + // key.mVisualInsetLeft, + // key.mVisualInsetRight, + // key.mMaxMoreKeysColumn, + }); + } + + private boolean equals(Key o) { + if (this == o) return true; + return o.mX == mX + && o.mY == mY + && o.mWidth == mWidth + && o.mHeight == mHeight + && o.mCode == mCode + && TextUtils.equals(o.mLabel, mLabel) + && TextUtils.equals(o.mHintLabel, mHintLabel) + && o.mIconId == mIconId + && o.mBackgroundType == mBackgroundType + && Arrays.equals(o.mMoreKeys, mMoreKeys) + && TextUtils.equals(o.mOutputText, mOutputText) + && o.mActionFlags == mActionFlags + && o.mLabelFlags == mLabelFlags; + } + + @Override + public int hashCode() { + return mHashCode; + } + + @Override + public boolean equals(Object o) { + return o instanceof Key && equals((Key)o); + } + + @Override + public String toString() { + return String.format("%s/%s %d,%d %dx%d %s/%s/%s", + Keyboard.printableCode(mCode), mLabel, mX, mY, mWidth, mHeight, mHintLabel, + KeyboardIconsSet.getIconName(mIconId), backgroundName(mBackgroundType)); + } + + private static String backgroundName(int backgroundType) { + switch (backgroundType) { + case BACKGROUND_TYPE_NORMAL: return "normal"; + case BACKGROUND_TYPE_FUNCTIONAL: return "functional"; + case BACKGROUND_TYPE_ACTION: return "action"; + case BACKGROUND_TYPE_STICKY_OFF: return "stickyOff"; + case BACKGROUND_TYPE_STICKY_ON: return "stickyOn"; + default: return null; + } + } + + public void markAsLeftEdge(Keyboard.Params params) { mHitBox.left = params.mHorizontalEdgesPadding; } - public void markAsRightEdge(KeyboardParams params) { + public void markAsRightEdge(Keyboard.Params params) { mHitBox.right = params.mOccupiedWidth - params.mHorizontalEdgesPadding; } - public void markAsTopEdge(KeyboardParams params) { + public void markAsTopEdge(Keyboard.Params params) { mHitBox.top = params.mTopPadding; } - public void markAsBottomEdge(KeyboardParams params) { + public void markAsBottomEdge(Keyboard.Params params) { mHitBox.bottom = params.mOccupiedHeight + params.mBottomPadding; } - public boolean isSticky() { - return mBackgroundType == BACKGROUND_TYPE_STICKY; + public final boolean isSpacer() { + return this instanceof Spacer; + } + + 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 isSpacer() { - return false; + public boolean altCodeWhileTyping() { + return (mActionFlags & ACTION_FLAGS_ALT_CODE_WHILE_TYPING) != 0; + } + + public boolean isLongPressEnabled() { + // We need not start long press timer on the key which has activated shifted letter. + return (mActionFlags & ACTION_FLAGS_ENABLE_LONG_PRESS) != 0 + && (mLabelFlags & LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED) == 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 +455,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,63 +468,57 @@ 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; - } - - public void setNeedsSpecialPopupHint(boolean needsSpecialPopupHint) { - mNeedsSpecialPopupHint = needsSpecialPopupHint; + return (mLabelFlags & LABEL_FLAGS_HAS_POPUP_HINT) != 0; } - public boolean needsSpecialPopupHint() { - return mNeedsSpecialPopupHint; - } - - public boolean hasUppercaseLetter() { - return (mLabelOption & LABEL_OPTION_HAS_UPPERCASE_LETTER) != 0; + public boolean hasShiftedLetterHint() { + return (mLabelFlags & LABEL_FLAGS_HAS_SHIFTED_LETTER_HINT) != 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() { - return mIcon; + public boolean isShiftedLetterActivated() { + return (mLabelFlags & LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED) != 0; } - public Drawable getPreviewIcon() { - return mPreviewIcon; + public Drawable getIcon(KeyboardIconsSet iconSet) { + return iconSet.getIconDrawable(mIconId); } - public void setIcon(Drawable icon) { - mIcon = icon; + public Drawable getDisabledIcon(KeyboardIconsSet iconSet) { + return iconSet.getIconDrawable(mDisabledIconId); } - public void setPreviewIcon(Drawable icon) { - mPreviewIcon = icon; + public Drawable getPreviewIcon(KeyboardIconsSet iconSet) { + return mPreviewIconId != KeyboardIconsSet.ICON_UNDEFINED + ? iconSet.getIconDrawable(mPreviewIconId) + : iconSet.getIconDrawable(mIconId); } /** @@ -420,10 +539,6 @@ public class Key { mPressed = false; } - public void setHighlightOn(boolean highlightOn) { - mHighlightOn = highlightOn; - } - public boolean isEnabled() { return mEnabled; } @@ -436,9 +551,9 @@ public class Key { * Detects if a point falls on this key. * @param x the x-coordinate of the point * @param y the y-coordinate of the point - * @return whether or not the point falls on the key. If the key is attached to an edge, it will - * assume that all points between the key and the edge are considered to be on the key. - * @see {@link #markAsLeftEdge(KeyboardParams)} etc. + * @return whether or not the point falls on the key. If the key is attached to an edge, it + * will assume that all points between the key and the edge are considered to be on the key. + * @see #markAsLeftEdge(Keyboard.Params) etc. */ public boolean isOnKey(int x, int y) { return mHitBox.contains(x, y); @@ -517,40 +632,32 @@ public class Key { * @see android.graphics.drawable.StateListDrawable#setState(int[]) */ public int[] getCurrentDrawableState() { - final boolean pressed = mPressed; - switch (mBackgroundType) { case BACKGROUND_TYPE_FUNCTIONAL: - return pressed ? KEY_STATE_FUNCTIONAL_PRESSED : KEY_STATE_FUNCTIONAL_NORMAL; + return mPressed ? KEY_STATE_FUNCTIONAL_PRESSED : KEY_STATE_FUNCTIONAL_NORMAL; case BACKGROUND_TYPE_ACTION: - return pressed ? KEY_STATE_ACTIVE_PRESSED : KEY_STATE_ACTIVE_NORMAL; - case BACKGROUND_TYPE_STICKY: - if (mHighlightOn) { - return pressed ? KEY_STATE_PRESSED_HIGHLIGHT_ON : KEY_STATE_NORMAL_HIGHLIGHT_ON; - } else { - return pressed ? KEY_STATE_PRESSED_HIGHLIGHT_OFF : KEY_STATE_NORMAL_HIGHLIGHT_OFF; - } + return mPressed ? KEY_STATE_ACTIVE_PRESSED : KEY_STATE_ACTIVE_NORMAL; + case BACKGROUND_TYPE_STICKY_OFF: + return mPressed ? KEY_STATE_PRESSED_HIGHLIGHT_OFF : KEY_STATE_NORMAL_HIGHLIGHT_OFF; + case BACKGROUND_TYPE_STICKY_ON: + return mPressed ? KEY_STATE_PRESSED_HIGHLIGHT_ON : KEY_STATE_NORMAL_HIGHLIGHT_ON; default: /* BACKGROUND_TYPE_NORMAL */ - return pressed ? KEY_STATE_PRESSED : KEY_STATE_NORMAL; + return mPressed ? KEY_STATE_PRESSED : KEY_STATE_NORMAL; } } public static class Spacer extends Key { - public Spacer(Resources res, KeyboardParams params, KeyboardBuilder.Row row, - XmlPullParser parser, KeyStyles keyStyles) { + public Spacer(Resources res, Keyboard.Params params, Keyboard.Builder.Row row, + XmlPullParser parser, KeyStyles keyStyles) throws XmlPullParserException { super(res, params, row, parser, keyStyles); } /** * This constructor is being used only for divider in more keys keyboard. */ - public Spacer(KeyboardParams params, Drawable icon, int x, int y, int width, int height) { - super(params, null, null, icon, Keyboard.CODE_DUMMY, null, x, y, width, height); - } - - @Override - public boolean isSpacer() { - return true; + protected Spacer(Keyboard.Params params, int x, int y, int width, int height) { + super(params, null, null, KeyboardIconsSet.ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED, + null, x, y, width, height); } } } diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java index 3298c41cf..bff491ffd 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 ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE = 2; private final int mKeyHysteresisDistanceSquared; @@ -39,7 +39,7 @@ public class KeyDetector { // working area private static final int MAX_NEARBY_KEYS = 12; private final int[] mDistances = new int[MAX_NEARBY_KEYS]; - private final int[] mIndices = new int[MAX_NEARBY_KEYS]; + private final Key[] mNeighborKeys = new Key[MAX_NEARBY_KEYS]; /** * This class handles key detection. @@ -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() { @@ -122,7 +122,7 @@ public class KeyDetector { private void initializeNearbyKeys() { Arrays.fill(mDistances, Integer.MAX_VALUE); - Arrays.fill(mIndices, NOT_A_KEY); + Arrays.fill(mNeighborKeys, null); } /** @@ -130,14 +130,14 @@ public class KeyDetector { * If the distance of two keys are the same, the key which the point is on should be considered * as a closer one. * - * @param keyIndex index of the key. + * @param key the key to be inserted into the nearby keys buffer. * @param distance distance between the key's edge and user touched point. * @param isOnKey true if the point is on the key. * @return order of the key in the nearby buffer, 0 if it is the nearest key. */ - private int sortNearbyKeys(int keyIndex, int distance, boolean isOnKey) { + private int sortNearbyKeys(Key key, int distance, boolean isOnKey) { final int[] distances = mDistances; - final int[] indices = mIndices; + final Key[] neighborKeys = mNeighborKeys; for (int insertPos = 0; insertPos < distances.length; insertPos++) { final int comparingDistance = distances[insertPos]; if (distance < comparingDistance || (distance == comparingDistance && isOnKey)) { @@ -145,79 +145,123 @@ public class KeyDetector { if (nextPos < distances.length) { System.arraycopy(distances, insertPos, distances, nextPos, distances.length - nextPos); - System.arraycopy(indices, insertPos, indices, nextPos, - indices.length - nextPos); + System.arraycopy(neighborKeys, insertPos, neighborKeys, nextPos, + neighborKeys.length - nextPos); } distances[insertPos] = distance; - indices[insertPos] = keyIndex; + neighborKeys[insertPos] = key; return insertPos; } } return distances.length; } - private void getNearbyKeyCodes(final int[] allCodes) { - final List<Key> keys = getKeyboard().mKeys; - final int[] indices = mIndices; + private void getNearbyKeyCodes(final int primaryCode, final int[] allCodes) { + final Key[] neighborKeys = mNeighborKeys; + final int maxCodesSize = allCodes.length; // allCodes[0] should always have the key code even if it is a non-letter key. - if (indices[0] == NOT_A_KEY) { + if (neighborKeys[0] == null) { allCodes[0] = NOT_A_CODE; return; } int numCodes = 0; - for (int j = 0; j < indices.length && numCodes < allCodes.length; j++) { - final int index = indices[j]; - if (index == NOT_A_KEY) + for (int j = 0; j < neighborKeys.length && numCodes < maxCodesSize; j++) { + final Key key = neighborKeys[j]; + if (key == null) break; - final int code = keys.get(index).mCode; + final int code = key.mCode; // filter out a non-letter key from nearby keys if (code < Keyboard.CODE_SPACE) continue; allCodes[numCodes++] = code; } + if (maxCodesSize <= numCodes) { + return; + } + if (primaryCode != NOT_A_CODE) { + final List<Integer> additionalChars = + mKeyboard.getAdditionalProximityChars().get(primaryCode); + if (additionalChars == null || additionalChars.size() == 0) { + return; + } + int currentCodesSize = numCodes; + allCodes[numCodes++] = ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE; + if (maxCodesSize <= numCodes) { + return; + } + // TODO: This is O(N^2). Assuming additionalChars.size() is up to 4 or 5. + for (int i = 0; i < additionalChars.size(); ++i) { + final int additionalChar = additionalChars.get(i); + boolean contains = false; + for (int j = 0; j < currentCodesSize; ++j) { + if (additionalChar == allCodes[j]) { + contains = true; + break; + } + } + if (!contains) { + allCodes[numCodes++] = additionalChar; + if (maxCodesSize <= numCodes) { + return; + } + } + } + } } /** - * 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) { - 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); initializeNearbyKeys(); - int primaryIndex = NOT_A_KEY; - for (final int index : mKeyboard.getNearestKeys(touchX, touchY)) { - final Key key = keys.get(index); + Key primaryKey = null; + for (final Key key: mKeyboard.getNearestKeys(touchX, touchY)) { 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; + final int insertedPosition = sortNearbyKeys(key, distance, isOnKey); + if (insertedPosition == 0 && isOnKey) { + primaryKey = key; + } } } if (allCodes != null && allCodes.length > 0) { - getNearbyKeyCodes(allCodes); + getNearbyKeyCodes(primaryKey != null ? primaryKey.mCode : NOT_A_CODE, 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 ? Keyboard.printableCode(key.mCode) : "none"; + } + + 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..28f71f443 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -16,14 +16,33 @@ package com.android.inputmethod.keyboard; -import android.graphics.drawable.Drawable; +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.TypedValue; +import android.util.Xml; +import android.view.InflateException; +import com.android.inputmethod.keyboard.internal.KeyStyles; import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; -import com.android.inputmethod.keyboard.internal.KeyboardParams; -import com.android.inputmethod.keyboard.internal.KeyboardShiftState; +import com.android.inputmethod.latin.LatinImeLogger; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.XmlParseUtils; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -47,7 +66,11 @@ import java.util.Set; * </pre> */ public class Keyboard { - /** Some common keys code. These should be aligned with values/keycodes.xml */ + private static final String TAG = Keyboard.class.getSimpleName(); + + /** Some common keys code. Must be positive. + * These should be aligned with values/keycodes.xml + */ public static final int CODE_ENTER = '\n'; public static final int CODE_TAB = '\t'; public static final int CODE_SPACE = ' '; @@ -64,20 +87,20 @@ public class Keyboard { public static final int CODE_CLOSING_ANGLE_BRACKET = '>'; public static final int CODE_DIGIT0 = '0'; public static final int CODE_PLUS = '+'; + private static final int MINIMUM_LETTER_CODE = CODE_TAB; - - /** Special keys code. These should be aligned with values/keycodes.xml */ - public static final int CODE_DUMMY = 0; + /** Special keys code. Must be negative. + * These should be aligned with values/keycodes.xml + */ public static final int CODE_SHIFT = -1; public static final int CODE_SWITCH_ALPHA_SYMBOL = -2; - public static final int CODE_CAPSLOCK = -3; - public static final int CODE_CANCEL = -4; - 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; + public static final int CODE_OUTPUT_TEXT = -3; + public static final int CODE_DELETE = -4; + public static final int CODE_SETTINGS = -5; + public static final int CODE_SHORTCUT = -6; + public static final int CODE_ACTION_ENTER = -7; // Code value representing the code is not specified. - public static final int CODE_UNSPECIFIED = -99; + public static final int CODE_UNSPECIFIED = -9; public final KeyboardId mId; public final int mThemeId; @@ -98,150 +121,278 @@ public class Keyboard { /** More keys keyboard template */ public final int mMoreKeysTemplate; - /** Maximum column for mini keyboard */ - public final int mMaxMiniKeyboardColumn; - - /** True if Right-To-Left keyboard */ - public final boolean mIsRtlKeyboard; + /** Maximum column for more keys keyboard */ + public final int mMaxMoreKeysKeyboardColumn; /** List of keys and icons in this keyboard */ - public final List<Key> mKeys; - public final List<Key> mShiftKeys; - public final Set<Key> mShiftLockKeys; - public final Map<Key, Drawable> mShiftedIcons; - public final Map<Key, Drawable> mUnshiftedIcons; + public final Set<Key> mKeys; + public final Set<Key> mShiftKeys; public final KeyboardIconsSet mIconsSet; - private final KeyboardShiftState mShiftState = new KeyboardShiftState(); + private final Map<Integer, Key> mKeyCache = new HashMap<Integer, Key>(); private final ProximityInfo mProximityInfo; - public Keyboard(KeyboardParams params) { + public final Map<Integer, List<Integer>> mAdditionalProximityChars; + + public Keyboard(Params params) { mId = params.mId; mThemeId = params.mThemeId; mOccupiedHeight = params.mOccupiedHeight; mOccupiedWidth = params.mOccupiedWidth; mMostCommonKeyHeight = params.mMostCommonKeyHeight; mMostCommonKeyWidth = params.mMostCommonKeyWidth; - mIsRtlKeyboard = params.mIsRtlKeyboard; mMoreKeysTemplate = params.mMoreKeysTemplate; - mMaxMiniKeyboardColumn = params.mMaxMiniKeyboardColumn; + mMaxMoreKeysKeyboardColumn = params.mMaxMoreKeysKeyboardColumn; mTopPadding = params.mTopPadding; mVerticalGap = params.mVerticalGap; - mKeys = Collections.unmodifiableList(params.mKeys); - mShiftKeys = Collections.unmodifiableList(params.mShiftKeys); - mShiftLockKeys = Collections.unmodifiableSet(params.mShiftLockKeys); - mShiftedIcons = Collections.unmodifiableMap(params.mShiftedIcons); - mUnshiftedIcons = Collections.unmodifiableMap(params.mUnshiftedIcons); + mKeys = Collections.unmodifiableSet(params.mKeys); + mShiftKeys = Collections.unmodifiableSet(params.mShiftKeys); mIconsSet = params.mIconsSet; + mAdditionalProximityChars = params.mAdditionalProximityChars; mProximityInfo = new ProximityInfo( params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight, - mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection); + mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection, + params.mAdditionalProximityChars); } public ProximityInfo getProximityInfo() { return mProximityInfo; } - public boolean hasShiftLockKey() { - return !mShiftLockKeys.isEmpty(); - } + public Key getKey(int code) { + if (code == CODE_UNSPECIFIED) { + return null; + } + final Integer keyCode = code; + if (mKeyCache.containsKey(keyCode)) { + return mKeyCache.get(keyCode); + } - public boolean 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)); + for (final Key key : mKeys) { + if (key.mCode == code) { + mKeyCache.put(keyCode, key); + return key; } } - mShiftState.setShiftLocked(newShiftLockState); - return true; + mKeyCache.put(keyCode, null); + return null; } + // TODO: Remove this method. public boolean isShiftLocked() { - return mShiftState.isShiftLocked(); + return mId.isAlphabetShiftLockedKeyboard(); } - public boolean isShiftLockShifted() { - return mShiftState.isShiftLockShifted(); + // TODO: Remove this method. + public boolean isShiftedOrShiftLocked() { + return mId.isAlphabetShiftedOrShiftLockedKeyboard(); } - 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)); - } - } - return mShiftState.setShifted(newShiftState); + // TODO: Remove this method. + public boolean isManualShifted() { + return mId.isAlphabetManualShiftedKeyboard(); } - public boolean isShiftedOrShiftLocked() { - return mShiftState.isShiftedOrShiftLocked(); + public static boolean isLetterCode(int code) { + return code >= MINIMUM_LETTER_CODE; } - public void setAutomaticTemporaryUpperCase() { - setShifted(true); - mShiftState.setAutomaticTemporaryUpperCase(); - } + public static class Params { + public KeyboardId mId; + public int mThemeId; - public boolean isAutomaticTemporaryUpperCase() { - return isAlphaKeyboard() && mShiftState.isAutomaticTemporaryUpperCase(); - } + /** Total height and width of the keyboard, including the paddings and keys */ + public int mOccupiedHeight; + public int mOccupiedWidth; - public boolean isManualTemporaryUpperCase() { - return isAlphaKeyboard() && mShiftState.isManualTemporaryUpperCase(); - } + /** Base height and width of the keyboard used to calculate rows' or keys' heights and + * widths + */ + public int mBaseHeight; + public int mBaseWidth; - public boolean isManualTemporaryUpperCaseFromAuto() { - return isAlphaKeyboard() && mShiftState.isManualTemporaryUpperCaseFromAuto(); - } + public int mTopPadding; + public int mBottomPadding; + public int mHorizontalEdgesPadding; + public int mHorizontalCenterPadding; - public KeyboardShiftState getKeyboardShiftState() { - return mShiftState; - } + public int mDefaultRowHeight; + public int mDefaultKeyWidth; + public int mHorizontalGap; + public int mVerticalGap; - public boolean isAlphaKeyboard() { - return mId.isAlphabetKeyboard(); - } + public int mMoreKeysTemplate; + public int mMaxMoreKeysKeyboardColumn; - public boolean isPhoneKeyboard() { - return mId.isPhoneKeyboard(); - } + public int GRID_WIDTH; + public int GRID_HEIGHT; - public boolean isNumberKeyboard() { - return mId.isNumberKeyboard(); - } + public final Set<Key> mKeys = new HashSet<Key>(); + public final Set<Key> mShiftKeys = new HashSet<Key>(); + public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); + // TODO: Should be in Key instead of Keyboard.Params? + public final Map<Integer, List<Integer>> mAdditionalProximityChars = + new HashMap<Integer, List<Integer>>(); + + public KeyboardSet.KeysCache mKeysCache; + + public int mMostCommonKeyHeight = 0; + public int mMostCommonKeyWidth = 0; + + public final TouchPositionCorrection mTouchPositionCorrection = + new TouchPositionCorrection(); + + public static class TouchPositionCorrection { + private static final int TOUCH_POSITION_CORRECTION_RECORD_SIZE = 3; + + public boolean mEnabled; + public float[] mXs; + public float[] mYs; + public float[] mRadii; + + public void load(String[] data) { + final int dataLength = data.length; + if (dataLength % TOUCH_POSITION_CORRECTION_RECORD_SIZE != 0) { + if (LatinImeLogger.sDBG) + throw new RuntimeException( + "the size of touch position correction data is invalid"); + return; + } - public CharSequence adjustLabelCase(CharSequence label) { - if (isShiftedOrShiftLocked() && !TextUtils.isEmpty(label) && label.length() < 3 - && Character.isLowerCase(label.charAt(0))) { - return label.toString().toUpperCase(mId.mLocale); + final int length = dataLength / TOUCH_POSITION_CORRECTION_RECORD_SIZE; + mXs = new float[length]; + mYs = new float[length]; + mRadii = new float[length]; + try { + for (int i = 0; i < dataLength; ++i) { + final int type = i % TOUCH_POSITION_CORRECTION_RECORD_SIZE; + final int index = i / TOUCH_POSITION_CORRECTION_RECORD_SIZE; + final float value = Float.parseFloat(data[i]); + if (type == 0) { + mXs[index] = value; + } else if (type == 1) { + mYs[index] = value; + } else { + mRadii[index] = value; + } + } + } catch (NumberFormatException e) { + if (LatinImeLogger.sDBG) { + throw new RuntimeException( + "the number format for touch position correction data is invalid"); + } + mXs = null; + mYs = null; + mRadii = null; + } + } + + public void setEnabled(boolean enabled) { + mEnabled = enabled; + } + + public boolean isValid() { + return mEnabled && mXs != null && mYs != null && mRadii != null + && mXs.length > 0 && mYs.length > 0 && mRadii.length > 0; + } + } + + protected void clearKeys() { + mKeys.clear(); + mShiftKeys.clear(); + clearHistogram(); + } + + public void onAddKey(Key newKey) { + final Key key = (mKeysCache != null) ? mKeysCache.get(newKey) : newKey; + mKeys.add(key); + updateHistogram(key); + if (key.mCode == Keyboard.CODE_SHIFT) { + mShiftKeys.add(key); + } + } + + private int mMaxHeightCount = 0; + private int mMaxWidthCount = 0; + private final Map<Integer, Integer> mHeightHistogram = new HashMap<Integer, Integer>(); + private final Map<Integer, Integer> mWidthHistogram = new HashMap<Integer, Integer>(); + + private void clearHistogram() { + mMostCommonKeyHeight = 0; + mMaxHeightCount = 0; + mHeightHistogram.clear(); + + mMaxWidthCount = 0; + mMostCommonKeyWidth = 0; + mWidthHistogram.clear(); + } + + private static int updateHistogramCounter(Map<Integer, Integer> histogram, Integer key) { + final int count = (histogram.containsKey(key) ? histogram.get(key) : 0) + 1; + histogram.put(key, count); + return count; + } + + private void updateHistogram(Key key) { + final Integer height = key.mHeight + key.mVerticalGap; + final int heightCount = updateHistogramCounter(mHeightHistogram, height); + if (heightCount > mMaxHeightCount) { + mMaxHeightCount = heightCount; + mMostCommonKeyHeight = height; + } + + final Integer width = key.mWidth + key.mHorizontalGap; + final int widthCount = updateHistogramCounter(mWidthHistogram, width); + if (widthCount > mMaxWidthCount) { + mMaxWidthCount = widthCount; + mMostCommonKeyWidth = width; + } } - return label; } /** - * Returns the indices of the keys that are closest to the given point. + * Returns the array of the keys that are closest to the given point. * @param x the x-coordinate of the point * @param y the y-coordinate of the point - * @return the array of integer indices for the nearest keys to the given point. If the given + * @return the array of the nearest keys to the given point. If the given * point is out of range, then an array of size zero is returned. */ - public int[] getNearestKeys(int x, int y) { - return mProximityInfo.getNearestKeys(x, y); + public Key[] getNearestKeys(int x, int y) { + // Avoid dead pixels at edges of the keyboard + final int adjustedX = Math.max(0, Math.min(x, mOccupiedWidth - 1)); + final int adjustedY = Math.max(0, Math.min(y, mOccupiedHeight - 1)); + return mProximityInfo.getNearestKeys(adjustedX, adjustedY); } - public static String themeName(int themeId) { + public Map<Integer, List<Integer>> getAdditionalProximityChars() { + return mAdditionalProximityChars; + } + + public static String printableCode(int code) { + switch (code) { + case CODE_SHIFT: return "shift"; + case CODE_SWITCH_ALPHA_SYMBOL: return "symbol"; + case CODE_OUTPUT_TEXT: return "text"; + case CODE_DELETE: return "delete"; + case CODE_SETTINGS: return "settings"; + case CODE_SHORTCUT: return "shortcut"; + case CODE_ACTION_ENTER: return "actionEnter"; + case CODE_UNSPECIFIED: return "unspec"; + case CODE_TAB: return "tab"; + case CODE_ENTER: return "enter"; + default: + if (code <= 0) Log.w(TAG, "Unknown non-positive key code=" + code); + if (code < CODE_SPACE) return String.format("'\\u%02x'", code); + if (code < 0x100) return String.format("'%c'", code); + return String.format("'\\u%04x'", code); + } + } + + public static String toThemeName(int themeId) { // This should be aligned with theme-*.xml resource files' themeId attribute. switch (themeId) { case 0: return "Basic"; @@ -253,4 +404,912 @@ public class Keyboard { default: return null; } } + + /** + * Keyboard Building helper. + * + * This class parses Keyboard XML file and eventually build a Keyboard. + * The Keyboard XML file looks like: + * <pre> + * >!-- xml/keyboard.xml --< + * >Keyboard keyboard_attributes*< + * >!-- Keyboard Content --< + * >Row row_attributes*< + * >!-- Row Content --< + * >Key key_attributes* /< + * >Spacer horizontalGap="0.2in" /< + * >include keyboardLayout="@xml/other_keys"< + * ... + * >/Row< + * >include keyboardLayout="@xml/other_rows"< + * ... + * >/Keyboard< + * </pre> + * The XML file which is included in other file must have >merge< as root element, + * such as: + * <pre> + * >!-- xml/other_keys.xml --< + * >merge< + * >Key key_attributes* /< + * ... + * >/merge< + * </pre> + * and + * <pre> + * >!-- xml/other_rows.xml --< + * >merge< + * >Row row_attributes*< + * >Key key_attributes* /< + * >/Row< + * ... + * >/merge< + * </pre> + * You can also use switch-case-default tags to select Rows and Keys. + * <pre> + * >switch< + * >case case_attribute*< + * >!-- Any valid tags at switch position --< + * >/case< + * ... + * >default< + * >!-- Any valid tags at switch position --< + * >/default< + * >/switch< + * </pre> + * You can declare Key style and specify styles within Key tags. + * <pre> + * >switch< + * >case mode="email"< + * >key-style styleName="f1-key" parentStyle="modifier-key" + * keyLabel=".com" + * /< + * >/case< + * >case mode="url"< + * >key-style styleName="f1-key" parentStyle="modifier-key" + * keyLabel="http://" + * /< + * >/case< + * >/switch< + * ... + * >Key keyStyle="shift-key" ... /< + * </pre> + */ + + public static class Builder<KP extends Params> { + private static final String BUILDER_TAG = "Keyboard.Builder"; + private static final boolean DEBUG = false; + + // Keyboard XML Tags + private static final String TAG_KEYBOARD = "Keyboard"; + private static final String TAG_ROW = "Row"; + private static final String TAG_KEY = "Key"; + private static final String TAG_SPACER = "Spacer"; + private static final String TAG_INCLUDE = "include"; + private static final String TAG_MERGE = "merge"; + private static final String TAG_SWITCH = "switch"; + private static final String TAG_CASE = "case"; + private static final String TAG_DEFAULT = "default"; + public static final String TAG_KEY_STYLE = "key-style"; + + private static final int DEFAULT_KEYBOARD_COLUMNS = 10; + private static final int DEFAULT_KEYBOARD_ROWS = 4; + + protected final KP mParams; + protected final Context mContext; + protected final Resources mResources; + private final DisplayMetrics mDisplayMetrics; + + private int mCurrentY = 0; + private Row mCurrentRow = null; + private boolean mLeftEdge; + private boolean mTopEdge; + private Key mRightEdgeKey = null; + private final KeyStyles mKeyStyles = new KeyStyles(); + + /** + * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate. + * Some of the key size defaults can be overridden per row from what the {@link Keyboard} + * defines. + */ + public static class Row { + // keyWidth enum constants + private static final int KEYWIDTH_NOT_ENUM = 0; + private static final int KEYWIDTH_FILL_RIGHT = -1; + private static final int KEYWIDTH_FILL_BOTH = -2; + + private final Params mParams; + /** Default width of a key in this row. */ + private float mDefaultKeyWidth; + /** Default height of a key in this row. */ + public final int mRowHeight; + + private final int mCurrentY; + // Will be updated by {@link Key}'s constructor. + private float mCurrentX; + + public Row(Resources res, Params params, XmlPullParser parser, int y) { + mParams = params; + TypedArray keyboardAttr = res.obtainAttributes(Xml.asAttributeSet(parser), + R.styleable.Keyboard); + mRowHeight = (int)Builder.getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_rowHeight, + params.mBaseHeight, params.mDefaultRowHeight); + keyboardAttr.recycle(); + TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser), + R.styleable.Keyboard_Key); + mDefaultKeyWidth = Builder.getDimensionOrFraction(keyAttr, + R.styleable.Keyboard_Key_keyWidth, + params.mBaseWidth, params.mDefaultKeyWidth); + keyAttr.recycle(); + + mCurrentY = y; + mCurrentX = 0.0f; + } + + public float getDefaultKeyWidth() { + return mDefaultKeyWidth; + } + + public void setDefaultKeyWidth(float defaultKeyWidth) { + mDefaultKeyWidth = defaultKeyWidth; + } + + public void setXPos(float keyXPos) { + mCurrentX = keyXPos; + } + + public void advanceXPos(float width) { + mCurrentX += width; + } + + public int getKeyY() { + return mCurrentY; + } + + public float getKeyX(TypedArray keyAttr) { + final int widthType = Builder.getEnumValue(keyAttr, + R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM); + if (widthType == KEYWIDTH_FILL_BOTH) { + // If keyWidth is fillBoth, the key width should start right after the nearest + // key on the left hand side. + return mCurrentX; + } + + final int keyboardRightEdge = mParams.mOccupiedWidth + - mParams.mHorizontalEdgesPadding; + if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) { + final float keyXPos = Builder.getDimensionOrFraction(keyAttr, + R.styleable.Keyboard_Key_keyXPos, mParams.mBaseWidth, 0); + if (keyXPos < 0) { + // If keyXPos is negative, the actual x-coordinate will be + // keyboardWidth + keyXPos. + // keyXPos shouldn't be less than mCurrentX because drawable area for this + // key starts at mCurrentX. Or, this key will overlaps the adjacent key on + // its left hand side. + return Math.max(keyXPos + keyboardRightEdge, mCurrentX); + } else { + return keyXPos + mParams.mHorizontalEdgesPadding; + } + } + return mCurrentX; + } + + public float getKeyWidth(TypedArray keyAttr) { + return getKeyWidth(keyAttr, mCurrentX); + } + + public float getKeyWidth(TypedArray keyAttr, float keyXPos) { + final int widthType = Builder.getEnumValue(keyAttr, + R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM); + switch (widthType) { + case KEYWIDTH_FILL_RIGHT: + case KEYWIDTH_FILL_BOTH: + final int keyboardRightEdge = + mParams.mOccupiedWidth - mParams.mHorizontalEdgesPadding; + // If keyWidth is fillRight, the actual key width will be determined to fill + // out the area up to the right edge of the keyboard. + // If keyWidth is fillBoth, the actual key width will be determined to fill out + // the area between the nearest key on the left hand side and the right edge of + // the keyboard. + return keyboardRightEdge - keyXPos; + default: // KEYWIDTH_NOT_ENUM + return Builder.getDimensionOrFraction(keyAttr, + R.styleable.Keyboard_Key_keyWidth, + mParams.mBaseWidth, mDefaultKeyWidth); + } + } + } + + public Builder(Context context, KP params) { + mContext = context; + final Resources res = context.getResources(); + mResources = res; + mDisplayMetrics = res.getDisplayMetrics(); + + mParams = params; + + setTouchPositionCorrectionData(context, params); + setAdditionalProximityChars(context, params); + + params.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width); + params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height); + } + + private static void setTouchPositionCorrectionData(Context context, Params params) { + final TypedArray a = context.obtainStyledAttributes( + null, R.styleable.Keyboard, R.attr.keyboardStyle, 0); + params.mThemeId = a.getInt(R.styleable.Keyboard_themeId, 0); + final int resourceId = a.getResourceId( + R.styleable.Keyboard_touchPositionCorrectionData, 0); + a.recycle(); + if (resourceId == 0) { + if (LatinImeLogger.sDBG) + Log.e(BUILDER_TAG, "touchPositionCorrectionData is not defined"); + return; + } + + final String[] data = context.getResources().getStringArray(resourceId); + params.mTouchPositionCorrection.load(data); + } + + private static void setAdditionalProximityChars(Context context, Params params) { + final String[] additionalChars = + context.getResources().getStringArray(R.array.additional_proximitychars); + int currentPrimaryIndex = 0; + for (int i = 0; i < additionalChars.length; ++i) { + final String additionalChar = additionalChars[i]; + if (TextUtils.isEmpty(additionalChar)) { + currentPrimaryIndex = 0; + } else if (currentPrimaryIndex == 0) { + currentPrimaryIndex = additionalChar.charAt(0); + params.mAdditionalProximityChars.put( + currentPrimaryIndex, new ArrayList<Integer>()); + } else if (currentPrimaryIndex != 0) { + final int c = additionalChar.charAt(0); + params.mAdditionalProximityChars.get(currentPrimaryIndex).add(c); + } + } + } + + public void setAutoGenerate(KeyboardSet.KeysCache keysCache) { + mParams.mKeysCache = keysCache; + } + + public Builder<KP> load(int xmlId, KeyboardId id) { + mParams.mId = id; + final XmlResourceParser parser = mResources.getXml(xmlId); + try { + parseKeyboard(parser); + } catch (XmlPullParserException e) { + Log.w(BUILDER_TAG, "keyboard XML parse error: " + e); + throw new IllegalArgumentException(e); + } catch (IOException e) { + Log.w(BUILDER_TAG, "keyboard XML parse error: " + e); + throw new RuntimeException(e); + } finally { + parser.close(); + } + return this; + } + + public void setTouchPositionCorrectionEnabled(boolean enabled) { + mParams.mTouchPositionCorrection.setEnabled(enabled); + } + + public Keyboard build() { + return new Keyboard(mParams); + } + + private int mIndent; + private static final String SPACES = " "; + + private static String spaces(int count) { + return (count < SPACES.length()) ? SPACES.substring(0, count) : SPACES; + } + + private void startTag(String format, Object ... args) { + Log.d(BUILDER_TAG, String.format(spaces(++mIndent * 2) + format, args)); + } + + private void endTag(String format, Object ... args) { + Log.d(BUILDER_TAG, String.format(spaces(mIndent-- * 2) + format, args)); + } + + private void startEndTag(String format, Object ... args) { + Log.d(BUILDER_TAG, String.format(spaces(++mIndent * 2) + format, args)); + mIndent--; + } + + private void parseKeyboard(XmlPullParser parser) + throws XmlPullParserException, IOException { + if (DEBUG) startTag("<%s> %s", TAG_KEYBOARD, mParams.mId); + int event; + while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { + if (event == XmlPullParser.START_TAG) { + final String tag = parser.getName(); + if (TAG_KEYBOARD.equals(tag)) { + parseKeyboardAttributes(parser); + startKeyboard(); + parseKeyboardContent(parser, false); + break; + } else { + throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD); + } + } + } + } + + private void parseKeyboardAttributes(XmlPullParser parser) { + final int displayWidth = mDisplayMetrics.widthPixels; + final TypedArray keyboardAttr = mContext.obtainStyledAttributes( + Xml.asAttributeSet(parser), R.styleable.Keyboard, R.attr.keyboardStyle, + R.style.Keyboard); + final TypedArray keyAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser), + R.styleable.Keyboard_Key); + try { + final int displayHeight = mDisplayMetrics.heightPixels; + final int keyboardHeight = (int)keyboardAttr.getDimension( + R.styleable.Keyboard_keyboardHeight, displayHeight / 2); + final int maxKeyboardHeight = (int)getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_maxKeyboardHeight, displayHeight, displayHeight / 2); + int minKeyboardHeight = (int)getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_minKeyboardHeight, displayHeight, displayHeight / 2); + if (minKeyboardHeight < 0) { + // Specified fraction was negative, so it should be calculated against display + // width. + minKeyboardHeight = -(int)getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_minKeyboardHeight, displayWidth, displayWidth / 2); + } + final Params params = mParams; + // Keyboard height will not exceed maxKeyboardHeight and will not be less than + // minKeyboardHeight. + params.mOccupiedHeight = Math.max( + Math.min(keyboardHeight, maxKeyboardHeight), minKeyboardHeight); + params.mOccupiedWidth = params.mId.mWidth; + params.mTopPadding = (int)getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_keyboardTopPadding, params.mOccupiedHeight, 0); + params.mBottomPadding = (int)getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_keyboardBottomPadding, params.mOccupiedHeight, 0); + params.mHorizontalEdgesPadding = (int)getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_keyboardHorizontalEdgesPadding, + mParams.mOccupiedWidth, 0); + + params.mBaseWidth = params.mOccupiedWidth - params.mHorizontalEdgesPadding * 2 + - params.mHorizontalCenterPadding; + params.mDefaultKeyWidth = (int)getDimensionOrFraction(keyAttr, + R.styleable.Keyboard_Key_keyWidth, params.mBaseWidth, + params.mBaseWidth / DEFAULT_KEYBOARD_COLUMNS); + params.mHorizontalGap = (int)getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_horizontalGap, params.mBaseWidth, 0); + params.mVerticalGap = (int)getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_verticalGap, params.mOccupiedHeight, 0); + params.mBaseHeight = params.mOccupiedHeight - params.mTopPadding + - params.mBottomPadding + params.mVerticalGap; + params.mDefaultRowHeight = (int)getDimensionOrFraction(keyboardAttr, + R.styleable.Keyboard_rowHeight, params.mBaseHeight, + params.mBaseHeight / DEFAULT_KEYBOARD_ROWS); + + params.mMoreKeysTemplate = keyboardAttr.getResourceId( + R.styleable.Keyboard_moreKeysTemplate, 0); + params.mMaxMoreKeysKeyboardColumn = keyAttr.getInt( + R.styleable.Keyboard_Key_maxMoreKeysColumn, 5); + + params.mIconsSet.loadIcons(keyboardAttr); + } finally { + keyAttr.recycle(); + keyboardAttr.recycle(); + } + } + + private void parseKeyboardContent(XmlPullParser parser, boolean skip) + throws XmlPullParserException, IOException { + int event; + while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { + if (event == XmlPullParser.START_TAG) { + final String tag = parser.getName(); + if (TAG_ROW.equals(tag)) { + Row row = parseRowAttributes(parser); + if (DEBUG) startTag("<%s>%s", TAG_ROW, skip ? " skipped" : ""); + if (!skip) { + startRow(row); + } + parseRowContent(parser, row, skip); + } else if (TAG_INCLUDE.equals(tag)) { + parseIncludeKeyboardContent(parser, skip); + } else if (TAG_SWITCH.equals(tag)) { + parseSwitchKeyboardContent(parser, skip); + } else if (TAG_KEY_STYLE.equals(tag)) { + parseKeyStyle(parser, skip); + } else { + throw new XmlParseUtils.IllegalStartTag(parser, TAG_ROW); + } + } else if (event == XmlPullParser.END_TAG) { + final String tag = parser.getName(); + if (DEBUG) endTag("</%s>", tag); + if (TAG_KEYBOARD.equals(tag)) { + endKeyboard(); + break; + } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag) + || TAG_MERGE.equals(tag)) { + break; + } else { + throw new XmlParseUtils.IllegalEndTag(parser, TAG_ROW); + } + } + } + } + + private Row parseRowAttributes(XmlPullParser parser) throws XmlPullParserException { + final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), + R.styleable.Keyboard); + try { + if (a.hasValue(R.styleable.Keyboard_horizontalGap)) + throw new XmlParseUtils.IllegalAttribute(parser, "horizontalGap"); + if (a.hasValue(R.styleable.Keyboard_verticalGap)) + throw new XmlParseUtils.IllegalAttribute(parser, "verticalGap"); + return new Row(mResources, mParams, parser, mCurrentY); + } finally { + a.recycle(); + } + } + + private void parseRowContent(XmlPullParser parser, Row row, boolean skip) + throws XmlPullParserException, IOException { + int event; + while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { + if (event == XmlPullParser.START_TAG) { + final String tag = parser.getName(); + if (TAG_KEY.equals(tag)) { + parseKey(parser, row, skip); + } else if (TAG_SPACER.equals(tag)) { + parseSpacer(parser, row, skip); + } else if (TAG_INCLUDE.equals(tag)) { + parseIncludeRowContent(parser, row, skip); + } else if (TAG_SWITCH.equals(tag)) { + parseSwitchRowContent(parser, row, skip); + } else if (TAG_KEY_STYLE.equals(tag)) { + parseKeyStyle(parser, skip); + } else { + throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY); + } + } else if (event == XmlPullParser.END_TAG) { + final String tag = parser.getName(); + if (DEBUG) endTag("</%s>", tag); + if (TAG_ROW.equals(tag)) { + if (!skip) { + endRow(row); + } + break; + } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag) + || TAG_MERGE.equals(tag)) { + break; + } else { + throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY); + } + } + } + } + + private void parseKey(XmlPullParser parser, Row row, boolean skip) + throws XmlPullParserException, IOException { + if (skip) { + XmlParseUtils.checkEndTag(TAG_KEY, parser); + if (DEBUG) startEndTag("<%s /> skipped", TAG_KEY); + } else { + final Key key = new Key(mResources, mParams, row, parser, mKeyStyles); + if (DEBUG) { + startEndTag("<%s%s %s moreKeys=%s />", TAG_KEY, + (key.isEnabled() ? "" : " disabled"), key, + Arrays.toString(key.mMoreKeys)); + } + XmlParseUtils.checkEndTag(TAG_KEY, parser); + endKey(key); + } + } + + private void parseSpacer(XmlPullParser parser, Row row, boolean skip) + throws XmlPullParserException, IOException { + if (skip) { + XmlParseUtils.checkEndTag(TAG_SPACER, parser); + if (DEBUG) startEndTag("<%s /> skipped", TAG_SPACER); + } else { + final Key.Spacer spacer = new Key.Spacer( + mResources, mParams, row, parser, mKeyStyles); + if (DEBUG) startEndTag("<%s />", TAG_SPACER); + XmlParseUtils.checkEndTag(TAG_SPACER, parser); + endKey(spacer); + } + } + + private void parseIncludeKeyboardContent(XmlPullParser parser, boolean skip) + throws XmlPullParserException, IOException { + parseIncludeInternal(parser, null, skip); + } + + private void parseIncludeRowContent(XmlPullParser parser, Row row, boolean skip) + throws XmlPullParserException, IOException { + parseIncludeInternal(parser, row, skip); + } + + private void parseIncludeInternal(XmlPullParser parser, Row row, boolean skip) + throws XmlPullParserException, IOException { + if (skip) { + XmlParseUtils.checkEndTag(TAG_INCLUDE, parser); + if (DEBUG) startEndTag("</%s> skipped", TAG_INCLUDE); + } else { + final AttributeSet attr = Xml.asAttributeSet(parser); + final TypedArray keyboardAttr = mResources.obtainAttributes(attr, + R.styleable.Keyboard_Include); + final TypedArray keyAttr = mResources.obtainAttributes(attr, + R.styleable.Keyboard_Key); + int keyboardLayout = 0; + float savedDefaultKeyWidth = 0; + try { + XmlParseUtils.checkAttributeExists(keyboardAttr, + R.styleable.Keyboard_Include_keyboardLayout, "keyboardLayout", + TAG_INCLUDE, parser); + keyboardLayout = keyboardAttr.getResourceId( + R.styleable.Keyboard_Include_keyboardLayout, 0); + if (row != null) { + savedDefaultKeyWidth = row.getDefaultKeyWidth(); + if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) { + // Override current x coordinate. + row.setXPos(row.getKeyX(keyAttr)); + } + if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyWidth)) { + // Override default key width. + row.setDefaultKeyWidth(row.getKeyWidth(keyAttr)); + } + } + } finally { + keyboardAttr.recycle(); + keyAttr.recycle(); + } + + XmlParseUtils.checkEndTag(TAG_INCLUDE, parser); + if (DEBUG) { + startEndTag("<%s keyboardLayout=%s />",TAG_INCLUDE, + mResources.getResourceEntryName(keyboardLayout)); + } + final XmlResourceParser parserForInclude = mResources.getXml(keyboardLayout); + try { + parseMerge(parserForInclude, row, skip); + } finally { + if (row != null) { + // Restore default key width. + row.setDefaultKeyWidth(savedDefaultKeyWidth); + } + parserForInclude.close(); + } + } + } + + private void parseMerge(XmlPullParser parser, Row row, boolean skip) + throws XmlPullParserException, IOException { + if (DEBUG) startTag("<%s>", TAG_MERGE); + int event; + while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { + if (event == XmlPullParser.START_TAG) { + final String tag = parser.getName(); + if (TAG_MERGE.equals(tag)) { + if (row == null) { + parseKeyboardContent(parser, skip); + } else { + parseRowContent(parser, row, skip); + } + break; + } else { + throw new XmlParseUtils.ParseException( + "Included keyboard layout must have <merge> root element", parser); + } + } + } + } + + private void parseSwitchKeyboardContent(XmlPullParser parser, boolean skip) + throws XmlPullParserException, IOException { + parseSwitchInternal(parser, null, skip); + } + + private void parseSwitchRowContent(XmlPullParser parser, Row row, boolean skip) + throws XmlPullParserException, IOException { + parseSwitchInternal(parser, row, skip); + } + + private void parseSwitchInternal(XmlPullParser parser, Row row, boolean skip) + throws XmlPullParserException, IOException { + if (DEBUG) startTag("<%s> %s", TAG_SWITCH, mParams.mId); + boolean selected = false; + int event; + while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { + if (event == XmlPullParser.START_TAG) { + final String tag = parser.getName(); + if (TAG_CASE.equals(tag)) { + selected |= parseCase(parser, row, selected ? true : skip); + } else if (TAG_DEFAULT.equals(tag)) { + selected |= parseDefault(parser, row, selected ? true : skip); + } else { + throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY); + } + } else if (event == XmlPullParser.END_TAG) { + final String tag = parser.getName(); + if (TAG_SWITCH.equals(tag)) { + if (DEBUG) endTag("</%s>", TAG_SWITCH); + break; + } else { + throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY); + } + } + } + } + + private boolean parseCase(XmlPullParser parser, Row row, boolean skip) + throws XmlPullParserException, IOException { + final boolean selected = parseCaseCondition(parser); + if (row == null) { + // Processing Rows. + parseKeyboardContent(parser, selected ? skip : true); + } else { + // Processing Keys. + parseRowContent(parser, row, selected ? skip : true); + } + return selected; + } + + private boolean parseCaseCondition(XmlPullParser parser) { + final KeyboardId id = mParams.mId; + if (id == null) + return true; + + final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), + R.styleable.Keyboard_Case); + try { + final boolean keyboardSetElementMatched = matchTypedValue(a, + R.styleable.Keyboard_Case_keyboardSetElement, id.mElementId, + KeyboardId.elementIdToName(id.mElementId)); + final boolean modeMatched = matchTypedValue(a, + R.styleable.Keyboard_Case_mode, id.mMode, KeyboardId.modeName(id.mMode)); + final boolean navigateActionMatched = matchBoolean(a, + R.styleable.Keyboard_Case_navigateAction, id.navigateAction()); + final boolean passwordInputMatched = matchBoolean(a, + R.styleable.Keyboard_Case_passwordInput, id.passwordInput()); + final boolean hasSettingsKeyMatched = matchBoolean(a, + R.styleable.Keyboard_Case_hasSettingsKey, id.hasSettingsKey()); + final boolean f2KeyModeMatched = matchInteger(a, + R.styleable.Keyboard_Case_f2KeyMode, id.f2KeyMode()); + final boolean clobberSettingsKeyMatched = matchBoolean(a, + R.styleable.Keyboard_Case_clobberSettingsKey, id.mClobberSettingsKey); + final boolean shortcutKeyEnabledMatched = matchBoolean(a, + R.styleable.Keyboard_Case_shortcutKeyEnabled, id.mShortcutKeyEnabled); + final boolean hasShortcutKeyMatched = matchBoolean(a, + R.styleable.Keyboard_Case_hasShortcutKey, id.mHasShortcutKey); + final boolean isMultiLineMatched = matchBoolean(a, + R.styleable.Keyboard_Case_isMultiLine, id.isMultiLine()); + final boolean imeActionMatched = matchInteger(a, + R.styleable.Keyboard_Case_imeAction, id.imeAction()); + final boolean localeCodeMatched = matchString(a, + R.styleable.Keyboard_Case_localeCode, id.mLocale.toString()); + final boolean languageCodeMatched = matchString(a, + R.styleable.Keyboard_Case_languageCode, id.mLocale.getLanguage()); + final boolean countryCodeMatched = matchString(a, + R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry()); + final boolean selected = keyboardSetElementMatched && modeMatched + && navigateActionMatched && passwordInputMatched && hasSettingsKeyMatched + && f2KeyModeMatched && clobberSettingsKeyMatched + && shortcutKeyEnabledMatched && hasShortcutKeyMatched && isMultiLineMatched + && imeActionMatched && localeCodeMatched && languageCodeMatched + && countryCodeMatched; + + if (DEBUG) { + startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE, + textAttr(a.getString(R.styleable.Keyboard_Case_keyboardSetElement), + "keyboardSetElement"), + textAttr(a.getString(R.styleable.Keyboard_Case_mode), "mode"), + booleanAttr(a, R.styleable.Keyboard_Case_navigateAction, + "navigateAction"), + booleanAttr(a, R.styleable.Keyboard_Case_passwordInput, + "passwordInput"), + booleanAttr(a, R.styleable.Keyboard_Case_hasSettingsKey, + "hasSettingsKey"), + textAttr(KeyboardId.f2KeyModeName( + a.getInt(R.styleable.Keyboard_Case_f2KeyMode, -1)), + "f2KeyMode"), + booleanAttr(a, R.styleable.Keyboard_Case_clobberSettingsKey, + "clobberSettingsKey"), + booleanAttr(a, R.styleable.Keyboard_Case_shortcutKeyEnabled, + "shortcutKeyEnabled"), + booleanAttr(a, R.styleable.Keyboard_Case_hasShortcutKey, + "hasShortcutKey"), + booleanAttr(a, R.styleable.Keyboard_Case_isMultiLine, + "isMultiLine"), + textAttr(a.getString(R.styleable.Keyboard_Case_imeAction), + "imeAction"), + textAttr(a.getString(R.styleable.Keyboard_Case_localeCode), + "localeCode"), + textAttr(a.getString(R.styleable.Keyboard_Case_languageCode), + "languageCode"), + textAttr(a.getString(R.styleable.Keyboard_Case_countryCode), + "countryCode"), + selected ? "" : " skipped"); + } + + return selected; + } finally { + a.recycle(); + } + } + + private static boolean matchInteger(TypedArray a, int index, int value) { + // If <case> does not have "index" attribute, that means this <case> is wild-card for + // the attribute. + return !a.hasValue(index) || a.getInt(index, 0) == value; + } + + private static boolean matchBoolean(TypedArray a, int index, boolean value) { + // If <case> does not have "index" attribute, that means this <case> is wild-card for + // the attribute. + return !a.hasValue(index) || a.getBoolean(index, false) == value; + } + + private static boolean matchString(TypedArray a, int index, String value) { + // If <case> does not have "index" attribute, that means this <case> is wild-card for + // the attribute. + return !a.hasValue(index) + || stringArrayContains(a.getString(index).split("\\|"), value); + } + + private static boolean matchTypedValue(TypedArray a, int index, int intValue, + String strValue) { + // If <case> does not have "index" attribute, that means this <case> is wild-card for + // the attribute. + final TypedValue v = a.peekValue(index); + if (v == null) + return true; + + if (isIntegerValue(v)) { + return intValue == a.getInt(index, 0); + } else if (isStringValue(v)) { + return stringArrayContains(a.getString(index).split("\\|"), strValue); + } + return false; + } + + private static boolean stringArrayContains(String[] array, String value) { + for (final String elem : array) { + if (elem.equals(value)) + return true; + } + return false; + } + + private boolean parseDefault(XmlPullParser parser, Row row, boolean skip) + throws XmlPullParserException, IOException { + if (DEBUG) startTag("<%s>", TAG_DEFAULT); + if (row == null) { + parseKeyboardContent(parser, skip); + } else { + parseRowContent(parser, row, skip); + } + return true; + } + + private void parseKeyStyle(XmlPullParser parser, boolean skip) + throws XmlPullParserException, IOException { + TypedArray keyStyleAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser), + R.styleable.Keyboard_KeyStyle); + TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser), + R.styleable.Keyboard_Key); + try { + if (!keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_styleName)) + throw new XmlParseUtils.ParseException("<" + TAG_KEY_STYLE + + "/> needs styleName attribute", parser); + if (DEBUG) { + startEndTag("<%s styleName=%s />%s", TAG_KEY_STYLE, + keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName), + skip ? " skipped" : ""); + } + if (!skip) + mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser); + } finally { + keyStyleAttr.recycle(); + keyAttrs.recycle(); + } + XmlParseUtils.checkEndTag(TAG_KEY_STYLE, parser); + } + + private void startKeyboard() { + mCurrentY += mParams.mTopPadding; + mTopEdge = true; + } + + private void startRow(Row row) { + addEdgeSpace(mParams.mHorizontalEdgesPadding, row); + mCurrentRow = row; + mLeftEdge = true; + mRightEdgeKey = null; + } + + private void endRow(Row row) { + if (mCurrentRow == null) + throw new InflateException("orphant end row tag"); + if (mRightEdgeKey != null) { + mRightEdgeKey.markAsRightEdge(mParams); + mRightEdgeKey = null; + } + addEdgeSpace(mParams.mHorizontalEdgesPadding, row); + mCurrentY += row.mRowHeight; + mCurrentRow = null; + mTopEdge = false; + } + + private void endKey(Key key) { + mParams.onAddKey(key); + if (mLeftEdge) { + key.markAsLeftEdge(mParams); + mLeftEdge = false; + } + if (mTopEdge) { + key.markAsTopEdge(mParams); + } + mRightEdgeKey = key; + } + + private void endKeyboard() { + // nothing to do here. + } + + private void addEdgeSpace(float width, Row row) { + row.advanceXPos(width); + mLeftEdge = false; + mRightEdgeKey = null; + } + + public static float getDimensionOrFraction(TypedArray a, int index, int base, + float defValue) { + final TypedValue value = a.peekValue(index); + if (value == null) + return defValue; + if (isFractionValue(value)) { + return a.getFraction(index, base, base, defValue); + } else if (isDimensionValue(value)) { + return a.getDimension(index, defValue); + } + return defValue; + } + + public static int getEnumValue(TypedArray a, int index, int defValue) { + final TypedValue value = a.peekValue(index); + if (value == null) + return defValue; + if (isIntegerValue(value)) { + return a.getInt(index, defValue); + } + return defValue; + } + + private static boolean isFractionValue(TypedValue v) { + return v.type == TypedValue.TYPE_FRACTION; + } + + private static boolean isDimensionValue(TypedValue v) { + return v.type == TypedValue.TYPE_DIMENSION; + } + + private static boolean isIntegerValue(TypedValue v) { + return v.type >= TypedValue.TYPE_FIRST_INT && v.type <= TypedValue.TYPE_LAST_INT; + } + + private static boolean isStringValue(TypedValue v) { + return v.type == TypedValue.TYPE_STRING; + } + + private static String textAttr(String value, String name) { + return value != null ? String.format(" %s=%s", name, value) : ""; + } + + private static String booleanAttr(TypedArray a, int index, String name) { + return a.hasValue(index) + ? String.format(" %s=%s", name, a.getBoolean(index, false)) : ""; + } + } } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java index 6f5420882..6e13b95b5 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java @@ -24,10 +24,8 @@ public interface KeyboardActionListener { * * @param primaryCode the unicode of the key being pressed. If the touch is not on a valid key, * the value will be zero. - * @param withSliding true if pressing has occurred because the user slid finger from other key - * to this key without releasing the finger. */ - public void onPress(int primaryCode, boolean withSliding); + public void onPressKey(int primaryCode); /** * Called when the user releases a key. This is sent after the {@link #onCodeInput} is called. @@ -37,7 +35,7 @@ public interface KeyboardActionListener { * @param withSliding true if releasing has occurred because the user slid finger from the key * to other key without releasing the finger. */ - public void onRelease(int primaryCode, boolean withSliding); + public void onReleaseKey(int primaryCode, boolean withSliding); /** * Send a key code to the listener. @@ -50,14 +48,17 @@ public interface KeyboardActionListener { * presses of a key adjacent to the intended key. * @param x x-coordinate pixel of touched event. If {@link #onCodeInput} is not called by * {@link PointerTracker#onTouchEvent} or so, the value should be - * {@link #NOT_A_TOUCH_COORDINATE}. + * {@link #NOT_A_TOUCH_COORDINATE}. If it's called on insertion from the suggestion + * strip, it should be {@link #SUGGESTION_STRIP_COORDINATE}. * @param y y-coordinate pixel of touched event. If {@link #onCodeInput} is not called by * {@link PointerTracker#onTouchEvent} or so, the value should be - * {@link #NOT_A_TOUCH_COORDINATE}. + * {@link #NOT_A_TOUCH_COORDINATE}. If it's called on insertion from the suggestion + * strip, it should be {@link #SUGGESTION_STRIP_COORDINATE}. */ public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y); public static final int NOT_A_TOUCH_COORDINATE = -1; + public static final int SUGGESTION_STRIP_COORDINATE = -2; /** * Sends a sequence of characters to the listener. @@ -79,9 +80,9 @@ public interface KeyboardActionListener { public static class Adapter implements KeyboardActionListener { @Override - public void onPress(int primaryCode, boolean withSliding) {} + public void onPressKey(int primaryCode) {} @Override - public void onRelease(int primaryCode, boolean withSliding) {} + public void onReleaseKey(int primaryCode, boolean withSliding) {} @Override public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {} @Override diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java index 2e4988fb0..3ab24933c 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java @@ -16,18 +16,18 @@ package com.android.inputmethod.keyboard; +import android.text.InputType; +import android.text.TextUtils; import android.view.inputmethod.EditorInfo; import com.android.inputmethod.compat.EditorInfoCompatUtils; import com.android.inputmethod.compat.InputTypeCompatUtils; -import com.android.inputmethod.latin.R; import java.util.Arrays; import java.util.Locale; /** - * Represents the parameters necessary to construct a new LatinKeyboard, - * which also serve as a unique identifier for each keyboard type. + * Unique identifier for each keyboard type. */ public class KeyboardId { public static final int MODE_TEXT = 0; @@ -37,104 +37,169 @@ public class KeyboardId { public static final int MODE_PHONE = 4; public static final int MODE_NUMBER = 5; - public static final int F2KEY_MODE_NONE = 0; - public static final int F2KEY_MODE_SETTINGS = 1; - public static final int F2KEY_MODE_SHORTCUT_IME = 2; - public static final int F2KEY_MODE_SHORTCUT_IME_OR_SETTINGS = 3; + public static final int ELEMENT_ALPHABET = 0; + public static final int ELEMENT_ALPHABET_MANUAL_SHIFTED = 1; + public static final int ELEMENT_ALPHABET_AUTOMATIC_SHIFTED = 2; + public static final int ELEMENT_ALPHABET_SHIFT_LOCKED = 3; + public static final int ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED = 4; + public static final int ELEMENT_SYMBOLS = 5; + public static final int ELEMENT_SYMBOLS_SHIFTED = 6; + public static final int ELEMENT_PHONE = 7; + public static final int ELEMENT_PHONE_SYMBOLS = 8; + public static final int ELEMENT_NUMBER = 9; + + private static final int F2KEY_MODE_NONE = 0; + private static final int F2KEY_MODE_SETTINGS = 1; + private static final int F2KEY_MODE_SHORTCUT_IME = 2; + private static final int F2KEY_MODE_SHORTCUT_IME_OR_SETTINGS = 3; + + private static final int IME_ACTION_CUSTOM_LABEL = EditorInfo.IME_MASK_ACTION + 1; public final Locale mLocale; public final int mOrientation; public final int mWidth; public final int mMode; - public final int mXmlId; - public final boolean mNavigateAction; - public final boolean mPasswordInput; - // TODO: Clean up these booleans and modes. - public final boolean mHasSettingsKey; - public final int mF2KeyMode; + public final int mElementId; + private final EditorInfo mEditorInfo; + private final boolean mSettingsKeyEnabled; public final boolean mClobberSettingsKey; public final boolean mShortcutKeyEnabled; public final boolean mHasShortcutKey; - public final int mImeAction; - - public final String mXmlName; - public final EditorInfo mAttribute; + public final String mCustomActionLabel; private final int mHashCode; - public KeyboardId(String xmlName, int xmlId, Locale locale, int orientation, int width, - int mode, EditorInfo attribute, 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; + public KeyboardId(int elementId, Locale locale, int orientation, int width, int mode, + EditorInfo editorInfo, boolean settingsKeyEnabled, boolean clobberSettingsKey, + boolean shortcutKeyEnabled, boolean hasShortcutKey) { this.mLocale = locale; this.mOrientation = orientation; this.mWidth = width; this.mMode = mode; - this.mXmlId = xmlId; - // Note: Turn off checking navigation flag to show TAB key for now. - this.mNavigateAction = InputTypeCompatUtils.isWebInputType(inputType); -// || EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions) -// || EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions); - this.mPasswordInput = InputTypeCompatUtils.isPasswordInputType(inputType) - || InputTypeCompatUtils.isVisiblePasswordInputType(inputType); - this.mHasSettingsKey = hasSettingsKey; - this.mF2KeyMode = f2KeyMode; + this.mElementId = elementId; + this.mEditorInfo = editorInfo; + this.mSettingsKeyEnabled = settingsKeyEnabled; this.mClobberSettingsKey = clobberSettingsKey; this.mShortcutKeyEnabled = shortcutKeyEnabled; this.mHasShortcutKey = hasShortcutKey; - // We are interested only in {@link EditorInfo#IME_MASK_ACTION} enum value and - // {@link EditorInfo#IME_FLAG_NO_ENTER_ACTION}. - this.mImeAction = imeOptions & ( - EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION); - - this.mXmlName = xmlName; - this.mAttribute = attribute; - - this.mHashCode = Arrays.hashCode(new Object[] { - locale, - orientation, - width, - mode, - xmlId, - mNavigateAction, - mPasswordInput, - hasSettingsKey, - f2KeyMode, - clobberSettingsKey, - shortcutKeyEnabled, - hasShortcutKey, - mImeAction, - }); + this.mCustomActionLabel = (editorInfo.actionLabel != null) + ? editorInfo.actionLabel.toString() : null; + + this.mHashCode = hashCode(this); } - public KeyboardId cloneWithNewXml(String xmlName, int xmlId) { - return new KeyboardId(xmlName, xmlId, mLocale, mOrientation, mWidth, mMode, mAttribute, - false, F2KEY_MODE_NONE, false, false, false); + private static int hashCode(KeyboardId id) { + return Arrays.hashCode(new Object[] { + id.mOrientation, + id.mElementId, + id.mMode, + id.mWidth, + id.navigateAction(), + id.passwordInput(), + id.mSettingsKeyEnabled, + id.mClobberSettingsKey, + id.mShortcutKeyEnabled, + id.mHasShortcutKey, + id.isMultiLine(), + id.imeAction(), + id.mCustomActionLabel, + id.mLocale + }); } - public int getXmlId() { - return mXmlId; + private boolean equals(KeyboardId other) { + if (other == this) + return true; + return other.mOrientation == this.mOrientation + && other.mElementId == this.mElementId + && other.mMode == this.mMode + && other.mWidth == this.mWidth + && other.navigateAction() == this.navigateAction() + && other.passwordInput() == this.passwordInput() + && other.mSettingsKeyEnabled == this.mSettingsKeyEnabled + && other.mClobberSettingsKey == this.mClobberSettingsKey + && other.mShortcutKeyEnabled == this.mShortcutKeyEnabled + && other.mHasShortcutKey == this.mHasShortcutKey + && other.isMultiLine() == this.isMultiLine() + && other.imeAction() == this.imeAction() + && TextUtils.equals(other.mCustomActionLabel, this.mCustomActionLabel) + && other.mLocale.equals(this.mLocale); } public boolean isAlphabetKeyboard() { - return mXmlId == R.xml.kbd_qwerty; + return mElementId < ELEMENT_SYMBOLS; + } + + public boolean isAlphabetShiftLockedKeyboard() { + return mElementId == ELEMENT_ALPHABET_SHIFT_LOCKED + || mElementId == ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED; + } + + public boolean isAlphabetShiftedOrShiftLockedKeyboard() { + return isAlphabetKeyboard() && mElementId != ELEMENT_ALPHABET; + } + + public boolean isAlphabetManualShiftedKeyboard() { + return mElementId == ELEMENT_ALPHABET_MANUAL_SHIFTED; } public boolean isSymbolsKeyboard() { - return mXmlId == R.xml.kbd_symbols || mXmlId == R.xml.kbd_symbols_shift; + return mElementId == ELEMENT_SYMBOLS || mElementId == ELEMENT_SYMBOLS_SHIFTED; } public boolean isPhoneKeyboard() { - return mMode == MODE_PHONE; + return mElementId == ELEMENT_PHONE || mElementId == ELEMENT_PHONE_SYMBOLS; } public boolean isPhoneShiftKeyboard() { - return mXmlId == R.xml.kbd_phone_shift; + return mElementId == ELEMENT_PHONE_SYMBOLS; + } + + public boolean navigateAction() { + // Note: Turn off checking navigation flag to show TAB key for now. + boolean navigateAction = InputTypeCompatUtils.isWebInputType(mEditorInfo.inputType); +// || EditorInfoCompatUtils.hasFlagNavigateNext(mImeOptions) +// || EditorInfoCompatUtils.hasFlagNavigatePrevious(mImeOptions); + return navigateAction; + } + + public boolean passwordInput() { + final int inputType = mEditorInfo.inputType; + return InputTypeCompatUtils.isPasswordInputType(inputType) + || InputTypeCompatUtils.isVisiblePasswordInputType(inputType); } - public boolean isNumberKeyboard() { - return mMode == MODE_NUMBER; + public boolean isMultiLine() { + return (mEditorInfo.inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) != 0; + } + + public int imeAction() { + if ((mEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) { + return EditorInfo.IME_ACTION_NONE; + } else if (mEditorInfo.actionLabel != null) { + return IME_ACTION_CUSTOM_LABEL; + } else { + return mEditorInfo.imeOptions & EditorInfo.IME_MASK_ACTION; + } + } + + public boolean hasSettingsKey() { + return mSettingsKeyEnabled && !mClobberSettingsKey; + } + + public int f2KeyMode() { + if (mClobberSettingsKey) { + // Never shows the Settings key + return KeyboardId.F2KEY_MODE_SHORTCUT_IME; + } + + if (mSettingsKeyEnabled) { + return KeyboardId.F2KEY_MODE_SETTINGS; + } else { + // It should be alright to fall back to the Settings key on 7-inch layouts + // even when the Settings key is not explicitly enabled. + return KeyboardId.F2KEY_MODE_SHORTCUT_IME_OR_SETTINGS; + } } @Override @@ -142,22 +207,6 @@ public class KeyboardId { return other instanceof KeyboardId && equals((KeyboardId) other); } - private boolean equals(KeyboardId other) { - return other.mLocale.equals(this.mLocale) - && other.mOrientation == this.mOrientation - && other.mWidth == this.mWidth - && other.mMode == this.mMode - && other.mXmlId == this.mXmlId - && other.mNavigateAction == this.mNavigateAction - && other.mPasswordInput == this.mPasswordInput - && other.mHasSettingsKey == this.mHasSettingsKey - && other.mF2KeyMode == this.mF2KeyMode - && other.mClobberSettingsKey == this.mClobberSettingsKey - && other.mShortcutKeyEnabled == this.mShortcutKeyEnabled - && other.mHasShortcutKey == this.mHasShortcutKey - && other.mImeAction == this.mImeAction; - } - @Override public int hashCode() { return mHashCode; @@ -165,22 +214,46 @@ public class KeyboardId { @Override public String toString() { - return String.format("[%s.xml %s %s%d %s %s %s%s%s%s%s%s%s]", - mXmlName, + return String.format("[%s %s %s%d %s %s %s%s%s%s%s%s%s]", + elementIdToName(mElementId), mLocale, (mOrientation == 1 ? "port" : "land"), mWidth, modeName(mMode), - EditorInfoCompatUtils.imeOptionsName(mImeAction), - f2KeyModeName(mF2KeyMode), + imeAction(), + f2KeyModeName(f2KeyMode()), (mClobberSettingsKey ? " clobberSettingsKey" : ""), - (mNavigateAction ? " navigateAction" : ""), - (mPasswordInput ? " passwordInput" : ""), - (mHasSettingsKey ? " hasSettingsKey" : ""), + (navigateAction() ? " navigateAction" : ""), + (passwordInput() ? " passwordInput" : ""), + (hasSettingsKey() ? " hasSettingsKey" : ""), (mShortcutKeyEnabled ? " shortcutKeyEnabled" : ""), (mHasShortcutKey ? " hasShortcutKey" : "") ); } + public static boolean equivalentEditorInfoForKeyboard(EditorInfo a, EditorInfo b) { + if (a == null && b == null) return true; + if (a == null || b == null) return false; + return a.inputType == b.inputType + && a.imeOptions == b.imeOptions + && TextUtils.equals(a.privateImeOptions, b.privateImeOptions); + } + + public static String elementIdToName(int elementId) { + switch (elementId) { + case ELEMENT_ALPHABET: return "alphabet"; + case ELEMENT_ALPHABET_MANUAL_SHIFTED: return "alphabetManualShifted"; + case ELEMENT_ALPHABET_AUTOMATIC_SHIFTED: return "alphabetAutomaticShifted"; + case ELEMENT_ALPHABET_SHIFT_LOCKED: return "alphabetShiftLocked"; + case ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED: return "alphabetShiftLockShifted"; + case ELEMENT_SYMBOLS: return "symbols"; + case ELEMENT_SYMBOLS_SHIFTED: return "symbolsShifted"; + case ELEMENT_PHONE: return "phone"; + case ELEMENT_PHONE_SYMBOLS: return "phoneSymbols"; + case ELEMENT_NUMBER: return "number"; + default: return null; + } + } + public static String modeName(int mode) { switch (mode) { case MODE_TEXT: return "text"; @@ -193,6 +266,11 @@ public class KeyboardId { } } + public static String actionName(int actionId) { + return (actionId == IME_ACTION_CUSTOM_LABEL) ? "actionCustomLabel" + : EditorInfoCompatUtils.imeActionName(actionId); + } + public static String f2KeyModeName(int f2KeyMode) { switch (f2KeyMode) { case F2KEY_MODE_NONE: return "none"; diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java new file mode 100644 index 000000000..f27170a89 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java @@ -0,0 +1,362 @@ +/* + * 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; + +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.util.Log; +import android.util.Xml; +import android.view.inputmethod.EditorInfo; + +import com.android.inputmethod.compat.EditorInfoCompatUtils; +import com.android.inputmethod.latin.LatinIME; +import com.android.inputmethod.latin.LatinImeLogger; +import com.android.inputmethod.latin.LocaleUtils; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.Utils; +import com.android.inputmethod.latin.XmlParseUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.lang.ref.SoftReference; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +/** + * This class represents a set of keyboards. Each of them represents a different keyboard + * specific to a keyboard state, such as alphabet, symbols, and so on. Layouts in the same + * {@link KeyboardSet} are related to each other. + * A {@link KeyboardSet} needs to be created for each {@link android.view.inputmethod.EditorInfo}. + */ +public class KeyboardSet { + private static final String TAG = KeyboardSet.class.getSimpleName(); + private static final boolean DEBUG_CACHE = LatinImeLogger.sDBG; + + private static final String TAG_KEYBOARD_SET = TAG; + private static final String TAG_ELEMENT = "Element"; + + private final Context mContext; + private final Params mParams; + + private static final HashMap<KeyboardId, SoftReference<Keyboard>> sKeyboardCache = + new HashMap<KeyboardId, SoftReference<Keyboard>>(); + private static final KeysCache sKeysCache = new KeysCache(); + + private static final EditorInfo EMPTY_EDITOR_INFO = new EditorInfo(); + + public static class KeyboardSetException extends RuntimeException { + public final KeyboardId mKeyboardId; + public KeyboardSetException(Throwable cause, KeyboardId keyboardId) { + super(cause); + mKeyboardId = keyboardId; + } + } + + public static class KeysCache { + private final Map<Key, Key> mMap; + + public KeysCache() { + mMap = new HashMap<Key, Key>(); + } + + public void clear() { + mMap.clear(); + } + + public Key get(Key key) { + final Key existingKey = mMap.get(key); + if (existingKey != null) { + // Reuse the existing element that equals to "key" without adding "key" to the map. + return existingKey; + } + mMap.put(key, key); + return key; + } + } + + static class Params { + int mMode; + EditorInfo mEditorInfo; + boolean mTouchPositionCorrectionEnabled; + boolean mSettingsKeyEnabled; + boolean mVoiceKeyEnabled; + boolean mVoiceKeyOnMain; + boolean mNoSettingsKey; + Locale mLocale; + int mOrientation; + int mWidth; + // KeyboardSet element id to keyboard layout XML id map. + final Map<Integer, Integer> mKeyboardSetElementIdToXmlIdMap = + new HashMap<Integer, Integer>(); + Params() {} + } + + public static void clearKeyboardCache() { + sKeyboardCache.clear(); + sKeysCache.clear(); + } + + private KeyboardSet(Context context, Params params) { + mContext = context; + mParams = params; + } + + public Keyboard getKeyboard(int baseKeyboardSetElementId) { + final int keyboardSetElementId; + switch (mParams.mMode) { + case KeyboardId.MODE_PHONE: + if (baseKeyboardSetElementId == KeyboardId.ELEMENT_SYMBOLS) { + keyboardSetElementId = KeyboardId.ELEMENT_PHONE_SYMBOLS; + } else { + keyboardSetElementId = KeyboardId.ELEMENT_PHONE; + } + break; + case KeyboardId.MODE_NUMBER: + keyboardSetElementId = KeyboardId.ELEMENT_NUMBER; + break; + default: + keyboardSetElementId = baseKeyboardSetElementId; + break; + } + + Integer keyboardXmlId = mParams.mKeyboardSetElementIdToXmlIdMap.get(keyboardSetElementId); + if (keyboardXmlId == null) { + keyboardXmlId = mParams.mKeyboardSetElementIdToXmlIdMap.get( + KeyboardId.ELEMENT_ALPHABET); + } + final KeyboardId id = getKeyboardId(keyboardSetElementId); + try { + return getKeyboard(mContext, keyboardXmlId, id); + } catch (RuntimeException e) { + throw new KeyboardSetException(e, id); + } + } + + private Keyboard getKeyboard(Context context, int keyboardXmlId, KeyboardId id) { + final Resources res = context.getResources(); + final SoftReference<Keyboard> ref = sKeyboardCache.get(id); + Keyboard keyboard = (ref == null) ? null : ref.get(); + if (keyboard == null) { + final Locale savedLocale = LocaleUtils.setSystemLocale(res, id.mLocale); + try { + final Keyboard.Builder<Keyboard.Params> builder = + new Keyboard.Builder<Keyboard.Params>(context, new Keyboard.Params()); + if (id.isAlphabetKeyboard()) { + builder.setAutoGenerate(sKeysCache); + } + builder.load(keyboardXmlId, id); + builder.setTouchPositionCorrectionEnabled(mParams.mTouchPositionCorrectionEnabled); + keyboard = builder.build(); + } finally { + LocaleUtils.setSystemLocale(res, savedLocale); + } + sKeyboardCache.put(id, new SoftReference<Keyboard>(keyboard)); + + if (DEBUG_CACHE) { + Log.d(TAG, "keyboard cache size=" + sKeyboardCache.size() + ": " + + ((ref == null) ? "LOAD" : "GCed") + " id=" + id); + } + } else if (DEBUG_CACHE) { + Log.d(TAG, "keyboard cache size=" + sKeyboardCache.size() + ": HIT id=" + id); + } + + return keyboard; + } + + // Note: The keyboard for each locale, shift state, and mode are represented as KeyboardSet + // element id that is a key in keyboard_set.xml. Also that file specifies which XML layout + // should be used for each keyboard. The KeyboardId is an internal key for Keyboard object. + private KeyboardId getKeyboardId(int keyboardSetElementId) { + final Params params = mParams; + final boolean isSymbols = (keyboardSetElementId == KeyboardId.ELEMENT_SYMBOLS + || keyboardSetElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED); + final boolean hasShortcutKey = params.mVoiceKeyEnabled + && (isSymbols != params.mVoiceKeyOnMain); + return new KeyboardId(keyboardSetElementId, params.mLocale, params.mOrientation, + params.mWidth, params.mMode, params.mEditorInfo, params.mSettingsKeyEnabled, + params.mNoSettingsKey, params.mVoiceKeyEnabled, hasShortcutKey); + } + + public static class Builder { + private final Context mContext; + private final String mPackageName; + private final Resources mResources; + private final EditorInfo mEditorInfo; + + private final Params mParams = new Params(); + + public Builder(Context context, EditorInfo editorInfo) { + mContext = context; + mPackageName = context.getPackageName(); + mResources = context.getResources(); + mEditorInfo = editorInfo; + final Params params = mParams; + + params.mMode = Utils.getKeyboardMode(editorInfo); + params.mEditorInfo = (editorInfo != null) ? editorInfo : EMPTY_EDITOR_INFO; + params.mNoSettingsKey = Utils.inPrivateImeOptions( + mPackageName, LatinIME.IME_OPTION_NO_SETTINGS_KEY, mEditorInfo); + } + + public Builder setScreenGeometry(int orientation, int widthPixels) { + mParams.mOrientation = orientation; + mParams.mWidth = widthPixels; + return this; + } + + // TODO: Use InputMethodSubtype object as argument. + public Builder setSubtype(Locale inputLocale, boolean asciiCapable, + boolean touchPositionCorrectionEnabled) { + final boolean deprecatedForceAscii = Utils.inPrivateImeOptions( + mPackageName, LatinIME.IME_OPTION_FORCE_ASCII, mEditorInfo); + final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii( + mParams.mEditorInfo.imeOptions) + || deprecatedForceAscii; + mParams.mLocale = (forceAscii && !asciiCapable) ? Locale.US : inputLocale; + mParams.mTouchPositionCorrectionEnabled = touchPositionCorrectionEnabled; + return this; + } + + public Builder setOptions(boolean settingsKeyEnabled, boolean voiceKeyEnabled, + boolean voiceKeyOnMain) { + mParams.mSettingsKeyEnabled = settingsKeyEnabled; + @SuppressWarnings("deprecation") + final boolean deprecatedNoMicrophone = Utils.inPrivateImeOptions( + null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, mEditorInfo); + final boolean noMicrophone = Utils.inPrivateImeOptions( + mPackageName, LatinIME.IME_OPTION_NO_MICROPHONE, mEditorInfo) + || deprecatedNoMicrophone; + mParams.mVoiceKeyEnabled = voiceKeyEnabled && !noMicrophone; + mParams.mVoiceKeyOnMain = voiceKeyOnMain; + return this; + } + + public KeyboardSet build() { + if (mParams.mOrientation == Configuration.ORIENTATION_UNDEFINED) + throw new RuntimeException("Screen geometry is not specified"); + if (mParams.mLocale == null) + throw new RuntimeException("KeyboardSet subtype is not specified"); + + final Locale savedLocale = LocaleUtils.setSystemLocale(mResources, mParams.mLocale); + try { + parseKeyboardSet(mResources, R.xml.keyboard_set); + } catch (Exception e) { + throw new RuntimeException(e.getMessage() + " in " + + mResources.getResourceName(R.xml.keyboard_set) + + " of locale " + mParams.mLocale); + } finally { + LocaleUtils.setSystemLocale(mResources, savedLocale); + } + return new KeyboardSet(mContext, mParams); + } + + private void parseKeyboardSet(Resources res, int resId) throws XmlPullParserException, + IOException { + final XmlResourceParser parser = res.getXml(resId); + try { + int event; + while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { + if (event == XmlPullParser.START_TAG) { + final String tag = parser.getName(); + if (TAG_KEYBOARD_SET.equals(tag)) { + parseKeyboardSetContent(parser); + } else { + throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD_SET); + } + } + } + } finally { + parser.close(); + } + } + + private void parseKeyboardSetContent(XmlPullParser parser) throws XmlPullParserException, + IOException { + int event; + while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { + if (event == XmlPullParser.START_TAG) { + final String tag = parser.getName(); + if (TAG_ELEMENT.equals(tag)) { + parseKeyboardSetElement(parser); + } else { + throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD_SET); + } + } else if (event == XmlPullParser.END_TAG) { + final String tag = parser.getName(); + if (TAG_KEYBOARD_SET.equals(tag)) { + break; + } else { + throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEYBOARD_SET); + } + } + } + } + + private void parseKeyboardSetElement(XmlPullParser parser) throws XmlPullParserException, + IOException { + final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), + R.styleable.KeyboardSet_Element); + try { + XmlParseUtils.checkAttributeExists(a, + R.styleable.KeyboardSet_Element_elementName, "elementName", + TAG_ELEMENT, parser); + XmlParseUtils.checkAttributeExists(a, + R.styleable.KeyboardSet_Element_elementKeyboard, "elementKeyboard", + TAG_ELEMENT, parser); + XmlParseUtils.checkEndTag(TAG_ELEMENT, parser); + + final int elementName = a.getInt( + R.styleable.KeyboardSet_Element_elementName, 0); + final int elementKeyboard = a.getResourceId( + R.styleable.KeyboardSet_Element_elementKeyboard, 0); + mParams.mKeyboardSetElementIdToXmlIdMap.put(elementName, elementKeyboard); + } finally { + a.recycle(); + } + } + } + + public static String parseKeyboardLocale(Resources res, int resId) + throws XmlPullParserException, IOException { + final XmlPullParser parser = res.getXml(resId); + if (parser == null) + return ""; + int event; + while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { + if (event == XmlPullParser.START_TAG) { + final String tag = parser.getName(); + if (TAG_KEYBOARD_SET.equals(tag)) { + final TypedArray keyboardSetAttr = res.obtainAttributes( + Xml.asAttributeSet(parser), R.styleable.KeyboardSet); + final String locale = keyboardSetAttr.getString( + R.styleable.KeyboardSet_keyboardLocale); + keyboardSetAttr.recycle(); + return locale; + } else { + throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD_SET); + } + } + } + return ""; + } +} diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index ac718fc62..5ba560d72 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -18,10 +18,7 @@ package com.android.inputmethod.keyboard; import android.content.Context; import android.content.SharedPreferences; -import android.content.res.Configuration; import android.content.res.Resources; -import android.text.TextUtils; -import android.util.DisplayMetrics; import android.util.Log; import android.view.ContextThemeWrapper; import android.view.InflateException; @@ -30,25 +27,22 @@ 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.KeyboardSet.KeyboardSetException; +import com.android.inputmethod.keyboard.PointerTracker.TimerProxy; +import com.android.inputmethod.keyboard.internal.KeyboardState; +import com.android.inputmethod.latin.DebugSettings; import com.android.inputmethod.latin.InputView; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; -import com.android.inputmethod.latin.LocaleUtils; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.Settings; +import com.android.inputmethod.latin.SettingsValues; import com.android.inputmethod.latin.SubtypeSwitcher; import com.android.inputmethod.latin.Utils; -import java.lang.ref.SoftReference; -import java.util.HashMap; -import java.util.Locale; - -public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceChangeListener { +public class KeyboardSwitcher implements KeyboardState.SwitchActions, + SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = KeyboardSwitcher.class.getSimpleName(); - private static final boolean DEBUG_CACHE = LatinImeLogger.sDBG; - public static final boolean DEBUG_STATE = false; public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20110916"; private static final int[] KEYBOARD_THEMES = { @@ -62,99 +56,26 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha private SubtypeSwitcher mSubtypeSwitcher; private SharedPreferences mPrefs; + private boolean mForceNonDistinctMultitouch; private InputView mCurrentInputView; private LatinKeyboardView mKeyboardView; private LatinIME mInputMethodService; - 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 KeyboardId mMainKeyboardId; - private KeyboardId mSymbolsKeyboardId; - private KeyboardId mSymbolsShiftedKeyboardId; + private KeyboardState mState; - private KeyboardId mCurrentId; - private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboardCache = - new HashMap<KeyboardId, SoftReference<LatinKeyboard>>(); - - private KeyboardLayoutState mSavedKeyboardState = new KeyboardLayoutState(); + private KeyboardSet mKeyboardSet; /** mIsAutoCorrectionActive indicates that auto corrected word will be input instead of * what user actually typed. */ private boolean mIsAutoCorrectionActive; - // TODO: Encapsulate these state handling to separate class and combine with ShiftKeyState - // and ModifierKeyState. - 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; - // The following states are used only on the distinct multi-touch panel devices. - private static final int SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL = 3; - private static final int SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE = 4; - private static final int SWITCH_STATE_CHORDING_ALPHA = 5; - private static final int SWITCH_STATE_CHORDING_SYMBOL = 6; - private int mSwitchState = SWITCH_STATE_ALPHA; - - private static String mLayoutSwitchBackSymbols; - private int mThemeIndex = -1; private Context mThemeContext; private static final KeyboardSwitcher sInstance = new KeyboardSwitcher(); - private class KeyboardLayoutState { - private boolean mIsValid; - private boolean mIsAlphabetMode; - private boolean mIsShiftLocked; - private boolean mIsShifted; - - public void save() { - if (mCurrentId == null) { - return; - } - mIsAlphabetMode = isAlphabetMode(); - if (mIsAlphabetMode) { - mIsShiftLocked = isShiftLocked(); - mIsShifted = !mIsShiftLocked && isShiftedOrShiftLocked(); - } else { - mIsShiftLocked = false; - mIsShifted = mCurrentId.equals(mSymbolsShiftedKeyboardId); - } - mIsValid = true; - } - - public KeyboardId getKeyboardId() { - if (!mIsValid) return mMainKeyboardId; - - if (mIsAlphabetMode) { - return mMainKeyboardId; - } else { - return mIsShifted ? mSymbolsShiftedKeyboardId : mSymbolsKeyboardId; - } - } - - public void restore() { - if (!mIsValid) return; - mIsValid = false; - - if (mIsAlphabetMode) { - final boolean isAlphabetMode = isAlphabetMode(); - final boolean isShiftLocked = isAlphabetMode && isShiftLocked(); - final boolean isShifted = !isShiftLocked && isShiftedOrShiftLocked(); - if (mIsShiftLocked != isShiftLocked) { - toggleCapsLock(); - } else if (mIsShifted != isShifted) { - onPressShift(false); - onReleaseShift(false); - } - } - } - } - public static KeyboardSwitcher getInstance() { return sInstance; } @@ -169,12 +90,14 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha private void initInternal(LatinIME ims, SharedPreferences prefs) { mInputMethodService = ims; - mPackageName = ims.getPackageName(); mResources = ims.getResources(); mPrefs = prefs; mSubtypeSwitcher = SubtypeSwitcher.getInstance(); + mState = new KeyboardState(this); setContextThemeWrapper(ims, getKeyboardThemeIndex(ims, prefs)); prefs.registerOnSharedPreferenceChangeListener(this); + mForceNonDistinctMultitouch = prefs.getBoolean( + DebugSettings.FORCE_NON_DISTINCT_MULTITOUCH_KEY, false); } private static int getKeyboardThemeIndex(Context context, SharedPreferences prefs) { @@ -195,26 +118,38 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha if (mThemeIndex != themeIndex) { mThemeIndex = themeIndex; mThemeContext = new ContextThemeWrapper(context, KEYBOARD_THEMES[themeIndex]); - mKeyboardCache.clear(); + KeyboardSet.clearKeyboardCache(); } } - public void loadKeyboard(EditorInfo editorInfo, Settings.Values settingsValues) { + public void loadKeyboard(EditorInfo editorInfo, SettingsValues settingsValues) { + final KeyboardSet.Builder builder = new KeyboardSet.Builder(mThemeContext, editorInfo); + builder.setScreenGeometry(mThemeContext.getResources().getConfiguration().orientation, + mThemeContext.getResources().getDisplayMetrics().widthPixels); + builder.setSubtype( + mSubtypeSwitcher.getInputLocale(), + mSubtypeSwitcher.currentSubtypeContainsExtraValueKey( + LatinIME.SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE), + mSubtypeSwitcher.currentSubtypeContainsExtraValueKey( + LatinIME.SUBTYPE_EXTRA_VALUE_SUPPORT_TOUCH_POSITION_CORRECTION)); + builder.setOptions( + settingsValues.isSettingsKeyEnabled(), + settingsValues.isVoiceKeyEnabled(editorInfo), + settingsValues.isVoiceKeyOnMain()); + mKeyboardSet = builder.build(); try { - mMainKeyboardId = getKeyboardId(editorInfo, false, false, settingsValues); - mSymbolsKeyboardId = getKeyboardId(editorInfo, true, false, settingsValues); - mSymbolsShiftedKeyboardId = getKeyboardId(editorInfo, true, true, settingsValues); - mLayoutSwitchBackSymbols = mResources.getString(R.string.layout_switch_back_symbols); - setKeyboard(getKeyboard(mSavedKeyboardState.getKeyboardId())); - mSavedKeyboardState.restore(); - } catch (RuntimeException e) { - Log.w(TAG, "loading keyboard failed: " + mMainKeyboardId, e); - LatinImeLogger.logOnException(mMainKeyboardId.toString(), e); + mState.onLoadKeyboard(mResources.getString(R.string.layout_switch_back_symbols)); + } catch (KeyboardSetException e) { + Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause()); + LatinImeLogger.logOnException(e.mKeyboardId.toString(), e.getCause()); + return; } } public void saveKeyboardState() { - mSavedKeyboardState.save(); + if (getKeyboard() != null) { + mState.onSaveKeyboardState(); + } } public void onFinishInputView() { @@ -229,532 +164,157 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha final Keyboard oldKeyboard = mKeyboardView.getKeyboard(); mKeyboardView.setKeyboard(keyboard); mCurrentInputView.setKeyboardGeometry(keyboard.mTopPadding); - mCurrentId = keyboard.mId; - mSwitchState = getSwitchState(mCurrentId); - updateShiftLockState(keyboard); mKeyboardView.setKeyPreviewPopupEnabled( - Settings.Values.isKeyPreviewPopupEnabled(mPrefs, mResources), - Settings.Values.getKeyPreviewPopupDismissDelay(mPrefs, mResources)); + SettingsValues.isKeyPreviewPopupEnabled(mPrefs, mResources), + SettingsValues.getKeyPreviewPopupDismissDelay(mPrefs, mResources)); + mKeyboardView.updateAutoCorrectionState(mIsAutoCorrectionActive); + // If the cached keyboard had been switched to another keyboard while the language was + // displayed on its spacebar, it might have had arbitrary text fade factor. In such + // case, we should reset the text fade factor. It is also applicable to shortcut key. + mKeyboardView.updateSpacebar(0.0f, + mSubtypeSwitcher.needsToDisplayLanguage(keyboard.mId.mLocale)); + mKeyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady()); final boolean localeChanged = (oldKeyboard == null) || !keyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale); mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged); - updateShiftState(); - } - - private int getSwitchState(KeyboardId id) { - return id.equals(mMainKeyboardId) ? SWITCH_STATE_ALPHA : SWITCH_STATE_SYMBOL_BEGIN; } - private void updateShiftLockState(Keyboard keyboard) { - if (mCurrentId.equals(mSymbolsShiftedKeyboardId)) { - // Symbol keyboard may have an ALT key that has a caps lock style indicator (a.k.a. - // sticky shift key). To show or dismiss the indicator, we need to call setShiftLocked() - // that takes care of the current keyboard having such ALT key or not. - keyboard.setShiftLocked(keyboard.hasShiftLockKey()); - } else if (mCurrentId.equals(mSymbolsKeyboardId)) { - // Symbol keyboard has an ALT key that has a caps lock style indicator. To disable the - // indicator, we need to call setShiftLocked(false). - keyboard.setShiftLocked(false); - } - } - - private LatinKeyboard getKeyboard(KeyboardId id) { - final SoftReference<LatinKeyboard> ref = mKeyboardCache.get(id); - LatinKeyboard keyboard = (ref == null) ? null : ref.get(); - if (keyboard == null) { - final Locale savedLocale = LocaleUtils.setSystemLocale(mResources, id.mLocale); - try { - final LatinKeyboard.Builder builder = new LatinKeyboard.Builder(mThemeContext); - builder.load(id); - builder.setTouchPositionCorrectionEnabled( - mSubtypeSwitcher.currentSubtypeContainsExtraValueKey( - LatinIME.SUBTYPE_EXTRA_VALUE_SUPPORT_TOUCH_POSITION_CORRECTION)); - keyboard = builder.build(); - } finally { - LocaleUtils.setSystemLocale(mResources, savedLocale); - } - mKeyboardCache.put(id, new SoftReference<LatinKeyboard>(keyboard)); - - if (DEBUG_CACHE) { - Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": " - + ((ref == null) ? "LOAD" : "GCed") + " id=" + id - + " theme=" + Keyboard.themeName(keyboard.mThemeId)); - } - } else if (DEBUG_CACHE) { - Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": HIT id=" + id - + " theme=" + Keyboard.themeName(keyboard.mThemeId)); - } - - keyboard.onAutoCorrectionStateChanged(mIsAutoCorrectionActive); - keyboard.setShiftLocked(false); - keyboard.setShifted(false); - // If the cached keyboard had been switched to another keyboard while the language was - // displayed on its spacebar, it might have had arbitrary text fade factor. In such case, - // we should reset the text fade factor. It is also applicable to shortcut key. - keyboard.setSpacebarTextFadeFactor(0.0f, null); - keyboard.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady(), null); - return keyboard; - } - - private KeyboardId getKeyboardId(EditorInfo editorInfo, final boolean isSymbols, - final boolean isShift, Settings.Values settingsValues) { - final int mode = Utils.getKeyboardMode(editorInfo); - final int xmlId; - switch (mode) { - case KeyboardId.MODE_PHONE: - xmlId = (isSymbols && isShift) ? R.xml.kbd_phone_shift : R.xml.kbd_phone; - break; - case KeyboardId.MODE_NUMBER: - xmlId = R.xml.kbd_number; - break; - default: - if (isSymbols) { - xmlId = isShift ? R.xml.kbd_symbols_shift : R.xml.kbd_symbols; - } else { - xmlId = R.xml.kbd_qwerty; - } - break; - } - - final boolean settingsKeyEnabled = settingsValues.isSettingsKeyEnabled(); - @SuppressWarnings("deprecation") - final boolean noMicrophone = Utils.inPrivateImeOptions( - mPackageName, LatinIME.IME_OPTION_NO_MICROPHONE, editorInfo) - || Utils.inPrivateImeOptions( - null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo); - final boolean voiceKeyEnabled = settingsValues.isVoiceKeyEnabled(editorInfo) - && !noMicrophone; - final boolean voiceKeyOnMain = settingsValues.isVoiceKeyOnMain(); - final boolean noSettingsKey = Utils.inPrivateImeOptions( - mPackageName, LatinIME.IME_OPTION_NO_SETTINGS_KEY, editorInfo); - final boolean hasSettingsKey = settingsKeyEnabled && !noSettingsKey; - final int f2KeyMode = getF2KeyMode(settingsKeyEnabled, noSettingsKey); - final boolean hasShortcutKey = voiceKeyEnabled && (isSymbols != voiceKeyOnMain); - final boolean forceAscii = Utils.inPrivateImeOptions( - mPackageName, LatinIME.IME_OPTION_FORCE_ASCII, editorInfo); - final boolean asciiCapable = mSubtypeSwitcher.currentSubtypeContainsExtraValueKey( - LatinIME.SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE); - final Locale locale = (forceAscii && !asciiCapable) - ? Locale.US : mSubtypeSwitcher.getInputLocale(); - final Configuration conf = mResources.getConfiguration(); - final DisplayMetrics dm = mResources.getDisplayMetrics(); - - return new KeyboardId( - mResources.getResourceEntryName(xmlId), xmlId, locale, conf.orientation, - dm.widthPixels, mode, editorInfo, hasSettingsKey, f2KeyMode, noSettingsKey, - voiceKeyEnabled, hasShortcutKey); - } - - public int getKeyboardMode() { - return mCurrentId != null ? mCurrentId.mMode : KeyboardId.MODE_TEXT; - } - - public boolean isAlphabetMode() { - return mCurrentId != null && mCurrentId.isAlphabetKeyboard(); - } - - public boolean isInputViewShown() { - return mCurrentInputView != null && mCurrentInputView.isShown(); - } - - public boolean isKeyboardAvailable() { - if (mKeyboardView != null) - return mKeyboardView.getKeyboard() != null; - return false; - } - - public LatinKeyboard getLatinKeyboard() { + public Keyboard getKeyboard() { if (mKeyboardView != null) { - final Keyboard keyboard = mKeyboardView.getKeyboard(); - if (keyboard instanceof LatinKeyboard) - return (LatinKeyboard)keyboard; + return mKeyboardView.getKeyboard(); } return null; } - 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; + /** + * Update keyboard shift state triggered by connected EditText status change. + */ + public void updateShiftState() { + mState.onUpdateShiftState(mInputMethodService.getCurrentAutoCapsState()); } - private boolean isShiftLockShifted() { - LatinKeyboard latinKeyboard = getLatinKeyboard(); - if (latinKeyboard != null) - return latinKeyboard.isShiftLockShifted(); - return false; + public void onPressKey(int code) { + if (isVibrateAndSoundFeedbackRequired()) { + mInputMethodService.hapticAndAudioFeedback(code); + } + mState.onPressKey(code); } - public boolean isAutomaticTemporaryUpperCase() { - LatinKeyboard latinKeyboard = getLatinKeyboard(); - if (latinKeyboard != null) - return latinKeyboard.isAutomaticTemporaryUpperCase(); - return false; + public void onReleaseKey(int code, boolean withSliding) { + mState.onReleaseKey(code, withSliding); } - public boolean isManualTemporaryUpperCase() { - LatinKeyboard latinKeyboard = getLatinKeyboard(); - if (latinKeyboard != null) - return latinKeyboard.isManualTemporaryUpperCase(); - return false; + public void onCancelInput() { + mState.onCancelInput(isSinglePointer()); } - private boolean isManualTemporaryUpperCaseFromAuto() { - LatinKeyboard latinKeyboard = getLatinKeyboard(); - if (latinKeyboard != null) - return latinKeyboard.isManualTemporaryUpperCaseFromAuto(); - return false; + // Implements {@link KeyboardState.SwitchActions}. + @Override + public void setAlphabetKeyboard() { + setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET)); } - private void setManualTemporaryUpperCase(boolean shifted) { - LatinKeyboard latinKeyboard = getLatinKeyboard(); - if (latinKeyboard != null) { - // 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(). - if (!hasDistinctMultitouch() && !shifted && latinKeyboard.isShiftLocked()) { - latinKeyboard.setShiftLocked(false); - } - if (latinKeyboard.setShifted(shifted)) { - mKeyboardView.invalidateAllKeys(); - } - } + // Implements {@link KeyboardState.SwitchActions}. + @Override + public void setAlphabetManualShiftedKeyboard() { + setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED)); } - private void setShiftLocked(boolean shiftLocked) { - LatinKeyboard latinKeyboard = getLatinKeyboard(); - if (latinKeyboard != null && latinKeyboard.setShiftLocked(shiftLocked)) { - mKeyboardView.invalidateAllKeys(); - } + // Implements {@link KeyboardState.SwitchActions}. + @Override + public void setAlphabetAutomaticShiftedKeyboard() { + setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED)); } - /** - * Toggle keyboard shift state triggered by user touch event. - */ - public void toggleShift() { - mInputMethodService.mHandler.cancelUpdateShiftState(); - if (DEBUG_STATE) - Log.d(TAG, "toggleShift:" - + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() - + " shiftKeyState=" + mShiftKeyState); - if (isAlphabetMode()) { - setManualTemporaryUpperCase(!isShiftedOrShiftLocked()); - } else { - toggleShiftInSymbol(); - } + // Implements {@link KeyboardState.SwitchActions}. + @Override + public void setAlphabetShiftLockedKeyboard() { + setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED)); } - public void toggleCapsLock() { - mInputMethodService.mHandler.cancelUpdateShiftState(); - if (DEBUG_STATE) - Log.d(TAG, "toggleCapsLock:" - + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() - + " shiftKeyState=" + mShiftKeyState); - if (isAlphabetMode()) { - if (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(); - } else { - setShiftLocked(true); - } - } + // Implements {@link KeyboardState.SwitchActions}. + @Override + public void setAlphabetShiftLockShiftedKeyboard() { + setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED)); } - private void setAutomaticTemporaryUpperCase() { - if (mKeyboardView == null) return; - final Keyboard keyboard = mKeyboardView.getKeyboard(); - if (keyboard == null) return; - keyboard.setAutomaticTemporaryUpperCase(); - mKeyboardView.invalidateAllKeys(); + // Implements {@link KeyboardState.SwitchActions}. + @Override + public void setSymbolsKeyboard() { + setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS)); } - /** - * 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()) { - // Only when shift key is releasing, automatic temporary upper case will be set. - setAutomaticTemporaryUpperCase(); - } else { - setManualTemporaryUpperCase(shiftKeyState.isMomentary()); - } - } - } else { - // In symbol keyboard mode, we should clear shift key state because only alphabet - // keyboard has shift key. - shiftKeyState.onRelease(); - } + // Implements {@link KeyboardState.SwitchActions}. + @Override + public void setSymbolsShiftedKeyboard() { + setKeyboard(mKeyboardSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS_SHIFTED)); } - public void changeKeyboardMode() { - if (DEBUG_STATE) - Log.d(TAG, "changeKeyboardMode:" - + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() - + " shiftKeyState=" + mShiftKeyState); - toggleKeyboardMode(); - if (isShiftLocked() && isAlphabetMode()) - setShiftLocked(true); - updateShiftState(); + // Implements {@link KeyboardState.SwitchActions}. + @Override + public void requestUpdatingShiftState() { + mState.onUpdateShiftState(mInputMethodService.getCurrentAutoCapsState()); } - 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()) { - // 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()) { - // 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()) { - // 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(); - mSwitchState = SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE; + // Implements {@link KeyboardState.SwitchActions}. + @Override + public void startDoubleTapTimer() { + final LatinKeyboardView keyboardView = getKeyboardView(); + if (keyboardView != null) { + final TimerProxy timer = keyboardView.getTimerProxy(); + timer.startDoubleTapTimer(); } } - 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()) { - // After chording input while normal state. - toggleShift(); - } else if (isShiftLocked() && !isShiftLockShifted() && shiftKeyState.isPressing() - && !withSliding) { - // Shift has been long pressed, ignore this release. - } else if (isShiftLocked() && !shiftKeyState.isIgnoring() && !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() - && !withSliding) { - // Shift has been pressed without chording while shifted state. - toggleShift(); - } else if (isManualTemporaryUpperCaseFromAuto() && shiftKeyState.isPressing() - && !withSliding) { - // Shift has been pressed without chording while manual temporary upper case - // transited from automatic temporary upper case. - toggleShift(); - } - } else { - // 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(); - } - } - shiftKeyState.onRelease(); - } - - public void onPressSymbol() { - if (DEBUG_STATE) - Log.d(TAG, "onPressSymbol:" - + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() - + " symbolKeyState=" + mSymbolKeyState); - changeKeyboardMode(); - mSymbolKeyState.onPress(); - mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL; - } - - public void onReleaseSymbol() { - if (DEBUG_STATE) - Log.d(TAG, "onReleaseSymbol:" - + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() - + " symbolKeyState=" + mSymbolKeyState); - // 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(); - } - mSymbolKeyState.onRelease(); + // Implements {@link KeyboardState.SwitchActions}. + @Override + public boolean isInDoubleTapTimeout() { + final LatinKeyboardView keyboardView = getKeyboardView(); + return (keyboardView != null) + ? keyboardView.getTimerProxy().isInDoubleTapTimeout() : false; } - public void onOtherKeyPressed() { - if (DEBUG_STATE) - Log.d(TAG, "onOtherKeyPressed:" - + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() - + " shiftKeyState=" + mShiftKeyState - + " symbolKeyState=" + mSymbolKeyState); - mShiftKeyState.onOtherKeyPressed(); - mSymbolKeyState.onOtherKeyPressed(); + // Implements {@link KeyboardState.SwitchActions}. + @Override + public void startLongPressTimer(int code) { + final LatinKeyboardView keyboardView = getKeyboardView(); + if (keyboardView != null) { + final TimerProxy timer = keyboardView.getTimerProxy(); + timer.startLongPressTimer(code); + } } - public void onCancelInput() { - // Snap back to the previous keyboard mode if the user cancels sliding input. - if (getPointerCount() == 1) { - if (mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL) { - changeKeyboardMode(); - } else if (mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE) { - toggleShift(); - } - } + // Implements {@link KeyboardState.SwitchActions}. + @Override + public void hapticAndAudioFeedback(int code) { + mInputMethodService.hapticAndAudioFeedback(code); } - private void toggleShiftInSymbol() { - if (isAlphabetMode()) - return; - final LatinKeyboard keyboard; - if (mCurrentId.equals(mSymbolsKeyboardId) - || !mCurrentId.equals(mSymbolsShiftedKeyboardId)) { - keyboard = getKeyboard(mSymbolsShiftedKeyboardId); - } else { - keyboard = getKeyboard(mSymbolsKeyboardId); - } - setKeyboard(keyboard); + public void onLongPressTimeout(int code) { + mState.onLongPressTimeout(code); } public boolean isInMomentarySwitchState() { - return mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL - || mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE; + return mState.isInMomentarySwitchState(); } - public boolean isVibrateAndSoundFeedbackRequired() { + private boolean isVibrateAndSoundFeedbackRequired() { 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() { return mKeyboardView != null && mKeyboardView.hasDistinctMultitouch(); } - private static boolean isSpaceCharacter(int c) { - return c == Keyboard.CODE_SPACE || c == Keyboard.CODE_ENTER; - } - - private static boolean isLayoutSwitchBackCharacter(int c) { - if (TextUtils.isEmpty(mLayoutSwitchBackSymbols)) return false; - if (mLayoutSwitchBackSymbols.indexOf(c) >= 0) return true; - return false; - } - /** - * Updates state machine to figure out when to automatically snap back to the previous mode. + * Updates state machine to figure out when to automatically switch back to the previous mode. */ - public void onKey(int code) { - if (DEBUG_STATE) - Log.d(TAG, "onKey: code=" + code + " switchState=" + mSwitchState - + " pointers=" + getPointerCount()); - switch (mSwitchState) { - case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL: - // Only distinct multi touch devices can be in this state. - // On non-distinct multi touch devices, mode change key is handled by - // {@link LatinIME#onCodeInput}, not by {@link LatinIME#onPress} and - // {@link LatinIME#onRelease}. So, on such devices, {@link #mSwitchState} starts - // from {@link #SWITCH_STATE_SYMBOL_BEGIN}, or {@link #SWITCH_STATE_ALPHA}, not from - // {@link #SWITCH_STATE_MOMENTARY}. - if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { - // Detected only the mode change key has been pressed, and then released. - if (mCurrentId.equals(mMainKeyboardId)) { - mSwitchState = SWITCH_STATE_ALPHA; - } else { - mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; - } - } else if (getPointerCount() == 1) { - // 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(); - } 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. - mSwitchState = SWITCH_STATE_CHORDING_ALPHA; - } - break; - case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE: - 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) { - // 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(); - mSwitchState = SWITCH_STATE_SYMBOL; - } else { - // Chording input is being started. The keyboard mode will be snapped back to the - // previous mode in {@link onReleaseShift} when the shift key is released. - mSwitchState = SWITCH_STATE_CHORDING_SYMBOL; - } - break; - case SWITCH_STATE_SYMBOL_BEGIN: - if (!isSpaceCharacter(code) && code >= 0) { - mSwitchState = SWITCH_STATE_SYMBOL; - } - // Snap back to alpha keyboard mode immediately if user types a quote character. - if (isLayoutSwitchBackCharacter(code)) { - changeKeyboardMode(); - } - break; - case SWITCH_STATE_SYMBOL: - case SWITCH_STATE_CHORDING_SYMBOL: - // 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(); - } - break; - } + public void onCodeInput(int code) { + mState.onCodeInput(code, isSinglePointer(), mInputMethodService.getCurrentAutoCapsState()); } public LatinKeyboardView getKeyboardView() { @@ -795,6 +355,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha mKeyboardView = (LatinKeyboardView) mCurrentInputView.findViewById(R.id.keyboard_view); mKeyboardView.setKeyboardActionListener(mInputMethodService); + if (mForceNonDistinctMultitouch) { + mKeyboardView.setDistinctMultitouch(false); + } // This always needs to be set since the accessibility state can // potentially change without the input view being re-created. @@ -804,13 +367,14 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } private void postSetInputView(final View newInputView) { - mInputMethodService.mHandler.post(new Runnable() { + final LatinIME latinIme = mInputMethodService; + latinIme.mHandler.post(new Runnable() { @Override public void run() { if (newInputView != null) { - mInputMethodService.setInputView(newInputView); + latinIme.setInputView(newInputView); } - mInputMethodService.updateInputViewShown(); + latinIme.updateInputViewShown(); } }); } @@ -825,31 +389,18 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } } + public void onNetworkStateChanged() { + if (mKeyboardView != null) { + mKeyboardView.updateShortcutKey(SubtypeSwitcher.getInstance().isShortcutImeReady()); + } + } + public void onAutoCorrectionStateChanged(boolean isAutoCorrection) { if (mIsAutoCorrectionActive != isAutoCorrection) { mIsAutoCorrectionActive = isAutoCorrection; - final LatinKeyboard keyboard = getLatinKeyboard(); - if (keyboard != null && keyboard.needsAutoCorrectionSpacebarLed()) { - final Key invalidatedKey = keyboard.onAutoCorrectionStateChanged(isAutoCorrection); - final LatinKeyboardView keyboardView = getKeyboardView(); - if (keyboardView != null) - keyboardView.invalidateKey(invalidatedKey); + if (mKeyboardView != null) { + mKeyboardView.updateAutoCorrectionState(isAutoCorrection); } } } - - private static int getF2KeyMode(boolean settingsKeyEnabled, boolean noSettingsKey) { - if (noSettingsKey) { - // Never shows the Settings key - return KeyboardId.F2KEY_MODE_SHORTCUT_IME; - } - - if (settingsKeyEnabled) { - return KeyboardId.F2KEY_MODE_SETTINGS; - } else { - // It should be alright to fall back to the Settings key on 7-inch layouts - // even when the Settings key is not explicitly enabled. - return KeyboardId.F2KEY_MODE_SHORTCUT_IME_OR_SETTINGS; - } - } } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index 04e672590..d65253ede 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -17,7 +17,6 @@ package com.android.inputmethod.keyboard; import android.content.Context; -import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -42,6 +41,7 @@ import com.android.inputmethod.compat.FrameLayoutCompatUtils; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; +import com.android.inputmethod.latin.Utils; import java.util.HashMap; @@ -54,12 +54,12 @@ import java.util.HashMap; * @attr ref R.styleable#KeyboardView_keyLargeLetterRatio * @attr ref R.styleable#KeyboardView_keyLabelRatio * @attr ref R.styleable#KeyboardView_keyHintLetterRatio - * @attr ref R.styleable#KeyboardView_keyUppercaseLetterRatio + * @attr ref R.styleable#KeyboardView_keyShiftedLetterHintRatio * @attr ref R.styleable#KeyboardView_keyHintLabelRatio * @attr ref R.styleable#KeyboardView_keyLabelHorizontalPadding * @attr ref R.styleable#KeyboardView_keyHintLetterPadding * @attr ref R.styleable#KeyboardView_keyPopupHintLetterPadding - * @attr ref R.styleable#KeyboardView_keyUppercaseLetterPadding + * @attr ref R.styleable#KeyboardView_keyShiftedLetterHintPadding * @attr ref R.styleable#KeyboardView_keyTextStyle * @attr ref R.styleable#KeyboardView_keyPreviewLayout * @attr ref R.styleable#KeyboardView_keyPreviewTextRatio @@ -69,8 +69,8 @@ import java.util.HashMap; * @attr ref R.styleable#KeyboardView_keyTextColorDisabled * @attr ref R.styleable#KeyboardView_keyHintLetterColor * @attr ref R.styleable#KeyboardView_keyHintLabelColor - * @attr ref R.styleable#KeyboardView_keyUppercaseLetterInactivatedColor - * @attr ref R.styleable#KeyboardView_keyUppercaseLetterActivatedColor + * @attr ref R.styleable#KeyboardView_keyShiftedLetterHintInactivatedColor + * @attr ref R.styleable#KeyboardView_keyShiftedLetterHintActivatedColor * @attr ref R.styleable#KeyboardView_shadowColor * @attr ref R.styleable#KeyboardView_shadowRadius */ @@ -102,7 +102,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { private final int mKeyPreviewLayoutId; protected final KeyPreviewDrawParams mKeyPreviewDrawParams; private boolean mShowKeyPreviewPopup = true; - private final int mDelayBeforePreview; private int mDelayAfterPreview; private ViewGroup mPreviewPlacer; @@ -134,8 +133,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { private final DrawingHandler mDrawingHandler = new DrawingHandler(this); public static class DrawingHandler extends StaticInnerHandlerWrapper<KeyboardView> { - private static final int MSG_SHOW_KEY_PREVIEW = 1; - private static final int MSG_DISMISS_KEY_PREVIEW = 2; + private static final int MSG_DISMISS_KEY_PREVIEW = 1; public DrawingHandler(KeyboardView outerInstance) { super(outerInstance); @@ -147,36 +145,12 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { if (keyboardView == null) return; final PointerTracker tracker = (PointerTracker) msg.obj; switch (msg.what) { - case MSG_SHOW_KEY_PREVIEW: - keyboardView.showKey(msg.arg1, tracker); - break; case MSG_DISMISS_KEY_PREVIEW: tracker.getKeyPreviewText().setVisibility(View.INVISIBLE); break; } } - public void showKeyPreview(long delay, int keyIndex, 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); - } else { - sendMessageDelayed( - obtainMessage(MSG_SHOW_KEY_PREVIEW, keyIndex, 0, tracker), delay); - } - } - - public void cancelShowKeyPreview(PointerTracker tracker) { - removeMessages(MSG_SHOW_KEY_PREVIEW, tracker); - } - - public void cancelAllShowKeyPreviews() { - removeMessages(MSG_SHOW_KEY_PREVIEW); - } - public void dismissKeyPreview(long delay, PointerTracker tracker) { sendMessageDelayed(obtainMessage(MSG_DISMISS_KEY_PREVIEW, tracker), delay); } @@ -190,12 +164,11 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } public void cancelAllMessages() { - cancelAllShowKeyPreviews(); cancelAllDismissKeyPreviews(); } } - private static class KeyDrawParams { + /* package */ static class KeyDrawParams { // XML attributes public final int mKeyTextColor; public final int mKeyTextInactivatedColor; @@ -203,20 +176,20 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { public final float mKeyLabelHorizontalPadding; public final float mKeyHintLetterPadding; public final float mKeyPopupHintLetterPadding; - public final float mKeyUppercaseLetterPadding; + public final float mKeyShiftedLetterHintPadding; public final int mShadowColor; public final float mShadowRadius; public final Drawable mKeyBackground; public final int mKeyHintLetterColor; public final int mKeyHintLabelColor; - public final int mKeyUppercaseLetterInactivatedColor; - public final int mKeyUppercaseLetterActivatedColor; + public final int mKeyShiftedLetterHintInactivatedColor; + public final int mKeyShiftedLetterHintActivatedColor; - private final float mKeyLetterRatio; + /* package */ final float mKeyLetterRatio; private final float mKeyLargeLetterRatio; private final float mKeyLabelRatio; private final float mKeyHintLetterRatio; - private final float mKeyUppercaseLetterRatio; + private final float mKeyShiftedLetterHintRatio; private final float mKeyHintLabelRatio; private static final float UNDEFINED_RATIO = -1.0f; @@ -225,7 +198,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { public int mKeyLargeLetterSize; public int mKeyLabelSize; public int mKeyHintLetterSize; - public int mKeyUppercaseLetterSize; + public int mKeyShiftedLetterHintSize; public int mKeyHintLabelSize; public KeyDrawParams(TypedArray a) { @@ -244,8 +217,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } mKeyLargeLetterRatio = getRatio(a, R.styleable.KeyboardView_keyLargeLetterRatio); mKeyHintLetterRatio = getRatio(a, R.styleable.KeyboardView_keyHintLetterRatio); - mKeyUppercaseLetterRatio = getRatio(a, - R.styleable.KeyboardView_keyUppercaseLetterRatio); + mKeyShiftedLetterHintRatio = getRatio(a, + R.styleable.KeyboardView_keyShiftedLetterHintRatio); mKeyHintLabelRatio = getRatio(a, R.styleable.KeyboardView_keyHintLabelRatio); mKeyLabelHorizontalPadding = a.getDimension( R.styleable.KeyboardView_keyLabelHorizontalPadding, 0); @@ -253,17 +226,17 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { R.styleable.KeyboardView_keyHintLetterPadding, 0); mKeyPopupHintLetterPadding = a.getDimension( R.styleable.KeyboardView_keyPopupHintLetterPadding, 0); - mKeyUppercaseLetterPadding = a.getDimension( - R.styleable.KeyboardView_keyUppercaseLetterPadding, 0); + mKeyShiftedLetterHintPadding = a.getDimension( + R.styleable.KeyboardView_keyShiftedLetterHintPadding, 0); mKeyTextColor = a.getColor(R.styleable.KeyboardView_keyTextColor, 0xFF000000); mKeyTextInactivatedColor = a.getColor( R.styleable.KeyboardView_keyTextInactivatedColor, 0xFF000000); mKeyHintLetterColor = a.getColor(R.styleable.KeyboardView_keyHintLetterColor, 0); mKeyHintLabelColor = a.getColor(R.styleable.KeyboardView_keyHintLabelColor, 0); - mKeyUppercaseLetterInactivatedColor = a.getColor( - R.styleable.KeyboardView_keyUppercaseLetterInactivatedColor, 0); - mKeyUppercaseLetterActivatedColor = a.getColor( - R.styleable.KeyboardView_keyUppercaseLetterActivatedColor, 0); + mKeyShiftedLetterHintInactivatedColor = a.getColor( + R.styleable.KeyboardView_keyShiftedLetterHintInactivatedColor, 0); + mKeyShiftedLetterHintActivatedColor = a.getColor( + R.styleable.KeyboardView_keyShiftedLetterHintActivatedColor, 0); mKeyTextStyle = Typeface.defaultFromStyle( a.getInt(R.styleable.KeyboardView_keyTextStyle, Typeface.NORMAL)); mShadowColor = a.getColor(R.styleable.KeyboardView_shadowColor, 0); @@ -279,12 +252,12 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { mKeyLabelSize = (int)(keyHeight * mKeyLabelRatio); mKeyLargeLetterSize = (int)(keyHeight * mKeyLargeLetterRatio); mKeyHintLetterSize = (int)(keyHeight * mKeyHintLetterRatio); - mKeyUppercaseLetterSize = (int)(keyHeight * mKeyUppercaseLetterRatio); + mKeyShiftedLetterHintSize = (int)(keyHeight * mKeyShiftedLetterHintRatio); mKeyHintLabelSize = (int)(keyHeight * mKeyHintLabelRatio); } } - protected static class KeyPreviewDrawParams { + /* package */ static class KeyPreviewDrawParams { // XML attributes. public final Drawable mPreviewBackground; public final Drawable mPreviewLeftBackground; @@ -295,6 +268,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { public final int mPreviewOffset; public final int mPreviewHeight; public final Typeface mKeyTextStyle; + public final int mLingerTimeout; private final float mPreviewTextRatio; private final float mKeyLetterRatio; @@ -324,6 +298,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { R.styleable.KeyboardView_keyPreviewHeight, 80); mPreviewTextRatio = getRatio(a, R.styleable.KeyboardView_keyPreviewTextRatio); mPreviewTextColor = a.getColor(R.styleable.KeyboardView_keyPreviewTextColor, 0); + mLingerTimeout = a.getInt(R.styleable.KeyboardView_keyPreviewLingerTimeout, 0); mKeyLetterRatio = keyDrawParams.mKeyLetterRatio; mKeyTextStyle = keyDrawParams.mKeyTextStyle; @@ -363,10 +338,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { mBackgroundDimAmount = a.getFloat(R.styleable.KeyboardView_backgroundDimAmount, 0.5f); a.recycle(); - final Resources res = getResources(); - - mDelayBeforePreview = res.getInteger(R.integer.config_delay_before_preview); - mDelayAfterPreview = res.getInteger(R.integer.config_delay_after_preview); + mDelayAfterPreview = mKeyPreviewDrawParams.mLingerTimeout; mPaint.setAntiAlias(true); mPaint.setTextAlign(Align.CENTER); @@ -374,7 +346,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } // Read fraction value in TypedArray as float. - private static float getRatio(TypedArray a, int index) { + /* package */ static float getRatio(TypedArray a, int index) { return a.getFraction(index, 1000, 1000, 1) / 1000.0f; } @@ -386,8 +358,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { * @param keyboard the keyboard to display in this view */ public void setKeyboard(Keyboard keyboard) { - // Remove any pending dismissing preview - mDrawingHandler.cancelAllShowKeyPreviews(); + // Remove any pending messages. + mDrawingHandler.cancelAllMessages(); if (mKeyboard != null) { PointerTracker.dismissAllKeyPreviews(); } @@ -475,7 +447,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { if (mKeyboard == null) return; - final boolean isManualTemporaryUpperCase = mKeyboard.isManualTemporaryUpperCase(); final KeyDrawParams params = mKeyDrawParams; if (mInvalidatedKey != null && mInvalidatedKeyRect.contains(mDirtyRect)) { // Draw a single key. @@ -483,8 +454,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { + getPaddingLeft(); final int keyDrawY = mInvalidatedKey.mY + getPaddingTop(); canvas.translate(keyDrawX, keyDrawY); - onBufferDrawKey(mInvalidatedKey, mKeyboard, canvas, mPaint, params, - isManualTemporaryUpperCase); + onDrawKey(mInvalidatedKey, canvas, mPaint, params); canvas.translate(-keyDrawX, -keyDrawY); } else { // Draw all keys. @@ -492,7 +462,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { final int keyDrawX = key.mX + key.mVisualInsetsLeft + getPaddingLeft(); final int keyDrawY = key.mY + getPaddingTop(); canvas.translate(keyDrawX, keyDrawY); - onBufferDrawKey(key, mKeyboard, canvas, mPaint, params, isManualTemporaryUpperCase); + onDrawKey(key, canvas, mPaint, params); canvas.translate(-keyDrawX, -keyDrawY); } } @@ -515,47 +485,51 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } } - private static void onBufferDrawKey(final Key key, final Keyboard keyboard, final Canvas canvas, - Paint paint, KeyDrawParams params, boolean isManualTemporaryUpperCase) { - final boolean debugShowAlign = LatinImeLogger.sVISUALDEBUG; - // Draw key background. + private void onDrawKey(Key key, Canvas canvas, Paint paint, KeyDrawParams params) { if (!key.isSpacer()) { - final int bgWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight - + params.mPadding.left + params.mPadding.right; - final int bgHeight = key.mHeight + params.mPadding.top + params.mPadding.bottom; - final int bgX = -params.mPadding.left; - final int bgY = -params.mPadding.top; - final int[] drawableState = key.getCurrentDrawableState(); - final Drawable background = params.mKeyBackground; - background.setState(drawableState); - final Rect bounds = background.getBounds(); - if (bgWidth != bounds.right || bgHeight != bounds.bottom) { - background.setBounds(0, 0, bgWidth, bgHeight); - } - canvas.translate(bgX, bgY); - background.draw(canvas); - if (debugShowAlign) { - drawRectangle(canvas, 0, 0, bgWidth, bgHeight, 0x80c00000, new Paint()); - } - canvas.translate(-bgX, -bgY); + onDrawKeyBackground(key, canvas, params); } + onDrawKeyTopVisuals(key, canvas, paint, params); + } + + // Draw key background. + protected void onDrawKeyBackground(Key key, Canvas canvas, KeyDrawParams params) { + final int bgWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight + + params.mPadding.left + params.mPadding.right; + final int bgHeight = key.mHeight + params.mPadding.top + params.mPadding.bottom; + final int bgX = -params.mPadding.left; + final int bgY = -params.mPadding.top; + final int[] drawableState = key.getCurrentDrawableState(); + final Drawable background = params.mKeyBackground; + background.setState(drawableState); + final Rect bounds = background.getBounds(); + if (bgWidth != bounds.right || bgHeight != bounds.bottom) { + background.setBounds(0, 0, bgWidth, bgHeight); + } + canvas.translate(bgX, bgY); + background.draw(canvas); + if (LatinImeLogger.sVISUALDEBUG) { + drawRectangle(canvas, 0, 0, bgWidth, bgHeight, 0x80c00000, new Paint()); + } + canvas.translate(-bgX, -bgY); + } - // Draw key top visuals. + // Draw key top visuals. + protected void onDrawKeyTopVisuals(Key key, Canvas canvas, Paint paint, KeyDrawParams params) { final int keyWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight; final int keyHeight = key.mHeight; final float centerX = keyWidth * 0.5f; final float centerY = keyHeight * 0.5f; - if (debugShowAlign) { + if (LatinImeLogger.sVISUALDEBUG) { drawRectangle(canvas, 0, 0, keyWidth, keyHeight, 0x800000c0, new Paint()); } // Draw key label. - final Drawable icon = key.getIcon(); + final Drawable icon = key.getIcon(mKeyboard.mIconsSet); float positionX = centerX; if (key.mLabel != null) { - // Switch the character to uppercase if shift is pressed - final CharSequence label = keyboard.adjustLabelCase(key.mLabel); + final String label = key.mLabel; // For characters, use large font. For labels like "Done", use smaller font. paint.setTypeface(key.selectTypeface(params.mKeyTextStyle)); final int labelSize = key.selectTextSize(params.mKeyLetterSize, @@ -598,11 +572,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { Math.min(1.0f, (keyWidth * MAX_LABEL_RATIO) / getLabelWidth(label, paint))); } - if (key.hasUppercaseLetter() && isManualTemporaryUpperCase) { - paint.setColor(params.mKeyTextInactivatedColor); - } else { - paint.setColor(params.mKeyTextColor); - } + paint.setColor(key.isShiftedLetterActivated() + ? params.mKeyTextInactivatedColor : params.mKeyTextColor); if (key.isEnabled()) { // Set a drop shadow for the text paint.setShadowLayer(params.mShadowRadius, 0, 0, params.mShadowColor); @@ -628,7 +599,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } } - if (debugShowAlign) { + if (LatinImeLogger.sVISUALDEBUG) { final Paint line = new Paint(); drawHorizontalLine(canvas, baseline, keyWidth, 0xc0008000, line); drawVerticalLine(canvas, positionX, keyHeight, 0xc0800080, line); @@ -637,18 +608,18 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { // Draw hint label. if (key.mHintLabel != null) { - final CharSequence hint = key.mHintLabel; + final String hint = key.mHintLabel; final int hintColor; final int hintSize; if (key.hasHintLabel()) { hintColor = params.mKeyHintLabelColor; hintSize = params.mKeyHintLabelSize; paint.setTypeface(Typeface.DEFAULT); - } else if (key.hasUppercaseLetter()) { - hintColor = isManualTemporaryUpperCase - ? params.mKeyUppercaseLetterActivatedColor - : params.mKeyUppercaseLetterInactivatedColor; - hintSize = params.mKeyUppercaseLetterSize; + } else if (key.hasShiftedLetterHint()) { + hintColor = key.isShiftedLetterActivated() + ? params.mKeyShiftedLetterHintActivatedColor + : params.mKeyShiftedLetterHintInactivatedColor; + hintSize = params.mKeyShiftedLetterHintSize; } else { // key.hasHintLetter() hintColor = params.mKeyHintLetterColor; hintSize = params.mKeyHintLetterSize; @@ -663,9 +634,9 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { hintX = positionX + getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) * 2; hintY = centerY + getCharHeight(KEY_LABEL_REFERENCE_CHAR, paint) / 2; paint.setTextAlign(Align.LEFT); - } else if (key.hasUppercaseLetter()) { + } else if (key.hasShiftedLetterHint()) { // The hint label is placed at top-right corner of the key. Used mainly on tablet. - hintX = keyWidth - params.mKeyUppercaseLetterPadding + hintX = keyWidth - params.mKeyShiftedLetterHintPadding - getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) / 2; hintY = -paint.ascent(); paint.setTextAlign(Align.CENTER); @@ -678,7 +649,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } canvas.drawText(hint, 0, hint.length(), hintX, hintY, paint); - if (debugShowAlign) { + if (LatinImeLogger.sVISUALDEBUG) { final Paint line = new Paint(); drawHorizontalLine(canvas, (int)hintY, keyWidth, 0xc0808000, line); drawVerticalLine(canvas, (int)hintX, keyHeight, 0xc0808000, line); @@ -703,33 +674,37 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } drawIcon(canvas, icon, iconX, iconY, iconWidth, iconHeight); - if (debugShowAlign) { + if (LatinImeLogger.sVISUALDEBUG) { final Paint line = new Paint(); drawVerticalLine(canvas, alignX, keyHeight, 0xc0800080, line); drawRectangle(canvas, iconX, iconY, iconWidth, iconHeight, 0x80c00000, line); } } - // Draw popup hint "..." at the bottom right corner of the key. - if ((key.hasPopupHint() && key.mMoreKeys != null && key.mMoreKeys.length > 0) - || key.needsSpecialPopupHint()) { - paint.setTextSize(params.mKeyHintLetterSize); - paint.setColor(params.mKeyHintLabelColor); - paint.setTextAlign(Align.CENTER); - final float hintX = keyWidth - params.mKeyHintLetterPadding - - getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) / 2; - final float hintY = keyHeight - params.mKeyPopupHintLetterPadding; - canvas.drawText(POPUP_HINT_CHAR, hintX, hintY, paint); - - if (debugShowAlign) { - final Paint line = new Paint(); - drawHorizontalLine(canvas, (int)hintY, keyWidth, 0xc0808000, line); - drawVerticalLine(canvas, (int)hintX, keyHeight, 0xc0808000, line); - } + if (key.hasPopupHint() && key.mMoreKeys != null && key.mMoreKeys.length > 0) { + drawKeyPopupHint(key, canvas, paint, params); } } - private static final Rect sTextBounds = new Rect(); + // Draw popup hint "..." at the bottom right corner of the key. + protected void drawKeyPopupHint(Key key, Canvas canvas, Paint paint, KeyDrawParams params) { + final int keyWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight; + final int keyHeight = key.mHeight; + + paint.setTextSize(params.mKeyHintLetterSize); + paint.setColor(params.mKeyHintLabelColor); + paint.setTextAlign(Align.CENTER); + final float hintX = keyWidth - params.mKeyHintLetterPadding + - getCharWidth(KEY_LABEL_REFERENCE_CHAR, paint) / 2; + final float hintY = keyHeight - params.mKeyPopupHintLetterPadding; + canvas.drawText(POPUP_HINT_CHAR, hintX, hintY, paint); + + if (LatinImeLogger.sVISUALDEBUG) { + final Paint line = new Paint(); + drawHorizontalLine(canvas, (int)hintY, keyWidth, 0xc0808000, line); + drawVerticalLine(canvas, (int)hintX, keyHeight, 0xc0808000, line); + } + } private static int getCharGeometryCacheKey(char reference, Paint paint) { final int labelSize = (int)paint.getTextSize(); @@ -746,42 +721,45 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } } - private static float getCharHeight(char[] character, Paint paint) { + // Working variable for the following methods. + private final Rect mTextBounds = new Rect(); + + private float getCharHeight(char[] character, Paint paint) { final Integer key = getCharGeometryCacheKey(character[0], paint); final Float cachedValue = sTextHeightCache.get(key); if (cachedValue != null) return cachedValue; - paint.getTextBounds(character, 0, 1, sTextBounds); - final float height = sTextBounds.height(); + paint.getTextBounds(character, 0, 1, mTextBounds); + final float height = mTextBounds.height(); sTextHeightCache.put(key, height); return height; } - private static float getCharWidth(char[] character, Paint paint) { + private float getCharWidth(char[] character, Paint paint) { final Integer key = getCharGeometryCacheKey(character[0], paint); final Float cachedValue = sTextWidthCache.get(key); if (cachedValue != null) return cachedValue; - paint.getTextBounds(character, 0, 1, sTextBounds); - final float width = sTextBounds.width(); + paint.getTextBounds(character, 0, 1, mTextBounds); + final float width = mTextBounds.width(); sTextWidthCache.put(key, width); return width; } - private static float getLabelWidth(CharSequence label, Paint paint) { - paint.getTextBounds(label.toString(), 0, label.length(), sTextBounds); - return sTextBounds.width(); + protected float getLabelWidth(CharSequence label, Paint paint) { + paint.getTextBounds(label.toString(), 0, label.length(), mTextBounds); + return mTextBounds.width(); } - public float getDefaultLabelWidth(CharSequence label, Paint paint) { + public float getDefaultLabelWidth(String label, Paint paint) { paint.setTextSize(mKeyDrawParams.mKeyLabelSize); paint.setTypeface(mKeyDrawParams.mKeyTextStyle); return getLabelWidth(label, paint); } - private static void drawIcon(Canvas canvas, Drawable icon, int x, int y, int width, + protected static void drawIcon(Canvas canvas, Drawable icon, int x, int y, int width, int height) { canvas.translate(x, y); icon.setBounds(0, 0, width, height); @@ -830,20 +808,14 @@ 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); + showKey(tracker); } } @Override - public void cancelShowKeyPreview(PointerTracker tracker) { - mDrawingHandler.cancelShowKeyPreview(tracker); - } - - @Override public void dismissKeyPreview(PointerTracker tracker) { - mDrawingHandler.cancelShowKeyPreview(tracker); mDrawingHandler.dismissKeyPreview(mDelayAfterPreview, tracker); } @@ -858,7 +830,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 +839,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) @@ -881,18 +853,17 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { if (key.mLabel != null) { // TODO Should take care of temporaryShiftLabel here. previewText.setCompoundDrawables(null, null, null, null); - if (key.mLabel.length() > 1) { + if (Utils.codePointCount(key.mLabel) > 1) { previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, params.mKeyLetterSize); previewText.setTypeface(Typeface.DEFAULT_BOLD); } else { previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, params.mPreviewTextSize); previewText.setTypeface(params.mKeyTextStyle); } - previewText.setText(mKeyboard.adjustLabelCase(key.mLabel)); + previewText.setText(key.mLabel); } else { - final Drawable previewIcon = key.getPreviewIcon(); previewText.setCompoundDrawables(null, null, null, - previewIcon != null ? previewIcon : key.getIcon()); + key.getPreviewIcon(mKeyboard.mIconsSet)); previewText.setText(null); } previewText.setBackgroundDrawable(params.mPreviewBackground); @@ -906,12 +877,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 @@ -932,6 +907,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { public void invalidateAllKeys() { mDirtyRect.union(0, 0, getWidth(), getHeight()); mBufferNeedsUpdate = true; + mInvalidatedKey = null; invalidate(); } diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java deleted file mode 100644 index 762039625..000000000 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.keyboard; - -import android.content.Context; -import android.content.res.Resources; -import android.content.res.Resources.Theme; -import android.content.res.TypedArray; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Paint.Align; -import android.graphics.PorterDuff; -import android.graphics.Rect; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.text.TextUtils; - -import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; -import com.android.inputmethod.keyboard.internal.KeyboardBuilder; -import com.android.inputmethod.keyboard.internal.KeyboardParams; -import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.SubtypeSwitcher; -import com.android.inputmethod.latin.Utils; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Locale; - -// TODO: We should remove this class -public class LatinKeyboard extends Keyboard { - private static final int SPACE_LED_LENGTH_PERCENT = 80; - - private final Resources mRes; - private final Theme mTheme; - private final SubtypeSwitcher mSubtypeSwitcher = SubtypeSwitcher.getInstance(); - - /* Space key and its icons, drawables and colors. */ - private final Key mSpaceKey; - private final Drawable mSpaceIcon; - private final boolean mAutoCorrectionSpacebarLedEnabled; - private final Drawable mAutoCorrectionSpacebarLedIcon; - private final int mSpacebarTextColor; - private final int mSpacebarTextShadowColor; - private float mSpacebarTextFadeFactor = 0.0f; - private final HashMap<Integer, BitmapDrawable> mSpaceDrawableCache = - new HashMap<Integer, BitmapDrawable>(); - private final boolean mIsSpacebarTriggeringPopupByLongPress; - - /* Shortcut key and its icons if available */ - private final Key mShortcutKey; - private final Drawable mEnabledShortcutIcon; - private final Drawable mDisabledShortcutIcon; - - // Height in space key the language name will be drawn. (proportional to space key height) - public static final float SPACEBAR_LANGUAGE_BASELINE = 0.6f; - // If the full language name needs to be smaller than this value to be drawn on space key, - // its short language name will be used instead. - private static final float MINIMUM_SCALE_OF_LANGUAGE_NAME = 0.8f; - - private static final String SMALL_TEXT_SIZE_OF_LANGUAGE_ON_SPACEBAR = "small"; - private static final String MEDIUM_TEXT_SIZE_OF_LANGUAGE_ON_SPACEBAR = "medium"; - - private LatinKeyboard(Context context, LatinKeyboardParams params) { - super(params); - mRes = context.getResources(); - mTheme = context.getTheme(); - - // The index of space key is available only after Keyboard constructor has finished. - mSpaceKey = params.mSpaceKey; - mSpaceIcon = (mSpaceKey != null) ? mSpaceKey.getIcon() : null; - - mShortcutKey = params.mShortcutKey; - mEnabledShortcutIcon = (mShortcutKey != null) ? mShortcutKey.getIcon() : null; - final int longPressSpaceKeyTimeout = - mRes.getInteger(R.integer.config_long_press_space_key_timeout); - mIsSpacebarTriggeringPopupByLongPress = (longPressSpaceKeyTimeout > 0); - - final TypedArray a = context.obtainStyledAttributes( - null, R.styleable.LatinKeyboard, R.attr.latinKeyboardStyle, R.style.LatinKeyboard); - mAutoCorrectionSpacebarLedEnabled = a.getBoolean( - R.styleable.LatinKeyboard_autoCorrectionSpacebarLedEnabled, false); - mAutoCorrectionSpacebarLedIcon = a.getDrawable( - R.styleable.LatinKeyboard_autoCorrectionSpacebarLedIcon); - mDisabledShortcutIcon = a.getDrawable(R.styleable.LatinKeyboard_disabledShortcutIcon); - mSpacebarTextColor = a.getColor(R.styleable.LatinKeyboard_spacebarTextColor, 0); - mSpacebarTextShadowColor = a.getColor( - R.styleable.LatinKeyboard_spacebarTextShadowColor, 0); - a.recycle(); - } - - private static class LatinKeyboardParams extends KeyboardParams { - public Key mSpaceKey = null; - public Key mShortcutKey = null; - - @Override - public void onAddKey(Key key) { - super.onAddKey(key); - - switch (key.mCode) { - case Keyboard.CODE_SPACE: - mSpaceKey = key; - break; - case Keyboard.CODE_SHORTCUT: - mShortcutKey = key; - break; - } - } - } - - public static class Builder extends KeyboardBuilder<LatinKeyboardParams> { - public Builder(Context context) { - super(context, new LatinKeyboardParams()); - } - - @Override - public Builder load(KeyboardId id) { - super.load(id); - return this; - } - - @Override - public LatinKeyboard build() { - return new LatinKeyboard(mContext, mParams); - } - } - - public void setSpacebarTextFadeFactor(float fadeFactor, KeyboardView view) { - mSpacebarTextFadeFactor = fadeFactor; - updateSpacebarForLocale(false); - if (view != null) - view.invalidateKey(mSpaceKey); - } - - private static int getSpacebarTextColor(int color, float fadeFactor) { - final int newColor = Color.argb((int)(Color.alpha(color) * fadeFactor), - Color.red(color), Color.green(color), Color.blue(color)); - return newColor; - } - - public void updateShortcutKey(boolean available, KeyboardView view) { - if (mShortcutKey == null) - return; - mShortcutKey.setEnabled(available); - mShortcutKey.setIcon(available ? mEnabledShortcutIcon : mDisabledShortcutIcon); - if (view != null) - view.invalidateKey(mShortcutKey); - } - - public boolean needsAutoCorrectionSpacebarLed() { - return mAutoCorrectionSpacebarLedEnabled; - } - - /** - * @return a key which should be invalidated. - */ - public Key onAutoCorrectionStateChanged(boolean isAutoCorrection) { - updateSpacebarForLocale(isAutoCorrection); - return mSpaceKey; - } - - @Override - public CharSequence adjustLabelCase(CharSequence label) { - if (isAlphaKeyboard() && isShiftedOrShiftLocked() && !TextUtils.isEmpty(label) - && label.length() < 3 && Character.isLowerCase(label.charAt(0))) { - return label.toString().toUpperCase(mId.mLocale); - } - return label; - } - - private void updateSpacebarForLocale(boolean isAutoCorrection) { - if (mSpaceKey == null) return; - final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance(); - if (imm == null) return; - // The "..." popup hint for triggering something by a long-pressing the spacebar - final boolean shouldShowInputMethodPicker = mIsSpacebarTriggeringPopupByLongPress - && Utils.hasMultipleEnabledIMEsOrSubtypes(imm, true /* include aux subtypes */); - mSpaceKey.setNeedsSpecialPopupHint(shouldShowInputMethodPicker); - // If application locales are explicitly selected. - if (mSubtypeSwitcher.needsToDisplayLanguage(mId.mLocale)) { - mSpaceKey.setIcon(getSpaceDrawable(mId.mLocale, isAutoCorrection)); - } else if (isAutoCorrection) { - mSpaceKey.setIcon(getSpaceDrawable(null, true)); - } else { - mSpaceKey.setIcon(mSpaceIcon); - } - } - - // Compute width of text with specified text size using paint. - private static int getTextWidth(Paint paint, String text, float textSize, Rect bounds) { - paint.setTextSize(textSize); - paint.getTextBounds(text, 0, text.length(), bounds); - return bounds.width(); - } - - // Layout local language name and left and right arrow on spacebar. - private static String layoutSpacebar(Paint paint, Locale locale, int width, - float origTextSize) { - final Rect bounds = new Rect(); - - // Estimate appropriate language name text size to fit in maxTextWidth. - String language = Utils.getFullDisplayName(locale, true); - int textWidth = getTextWidth(paint, language, origTextSize, bounds); - // Assuming text width and text size are proportional to each other. - float textSize = origTextSize * Math.min(width / textWidth, 1.0f); - // allow variable text size - textWidth = getTextWidth(paint, language, textSize, bounds); - // If text size goes too small or text does not fit, use middle or short name - final boolean useMiddleName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME) - || (textWidth > width); - - final boolean useShortName; - if (useMiddleName) { - language = Utils.getMiddleDisplayLanguage(locale); - textWidth = getTextWidth(paint, language, origTextSize, bounds); - textSize = origTextSize * Math.min(width / textWidth, 1.0f); - useShortName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME) - || (textWidth > width); - } else { - useShortName = false; - } - - if (useShortName) { - language = Utils.getShortDisplayLanguage(locale); - textWidth = getTextWidth(paint, language, origTextSize, bounds); - textSize = origTextSize * Math.min(width / textWidth, 1.0f); - } - paint.setTextSize(textSize); - - return language; - } - - private BitmapDrawable getSpaceDrawable(Locale locale, boolean isAutoCorrection) { - final Integer hashCode = Arrays.hashCode( - new Object[] { locale, isAutoCorrection, mSpacebarTextFadeFactor }); - final BitmapDrawable cached = mSpaceDrawableCache.get(hashCode); - if (cached != null) { - return cached; - } - final BitmapDrawable drawable = new BitmapDrawable(mRes, drawSpacebar( - locale, isAutoCorrection, mSpacebarTextFadeFactor)); - mSpaceDrawableCache.put(hashCode, drawable); - return drawable; - } - - private Bitmap drawSpacebar(Locale inputLocale, boolean isAutoCorrection, - float textFadeFactor) { - final int width = mSpaceKey.mWidth; - final int height = mSpaceIcon != null ? mSpaceIcon.getIntrinsicHeight() : mSpaceKey.mHeight; - final Bitmap buffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - final Canvas canvas = new Canvas(buffer); - final Resources res = mRes; - canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); - - // If application locales are explicitly selected. - if (inputLocale != null) { - final Paint paint = new Paint(); - paint.setAntiAlias(true); - paint.setTextAlign(Align.CENTER); - - final String textSizeOfLanguageOnSpacebar = res.getString( - R.string.config_text_size_of_language_on_spacebar, - SMALL_TEXT_SIZE_OF_LANGUAGE_ON_SPACEBAR); - final int textStyle; - final int defaultTextSize; - if (MEDIUM_TEXT_SIZE_OF_LANGUAGE_ON_SPACEBAR.equals(textSizeOfLanguageOnSpacebar)) { - textStyle = android.R.style.TextAppearance_Medium; - defaultTextSize = 18; - } else { - textStyle = android.R.style.TextAppearance_Small; - defaultTextSize = 14; - } - - final String language = layoutSpacebar(paint, inputLocale, width, getTextSizeFromTheme( - mTheme, textStyle, defaultTextSize)); - - // Draw language text with shadow - // In case there is no space icon, we will place the language text at the center of - // spacebar. - final float descent = paint.descent(); - final float textHeight = -paint.ascent() + descent; - final float baseline = (mSpaceIcon != null) ? height * SPACEBAR_LANGUAGE_BASELINE - : height / 2 + textHeight / 2; - paint.setColor(getSpacebarTextColor(mSpacebarTextShadowColor, textFadeFactor)); - canvas.drawText(language, width / 2, baseline - descent - 1, paint); - paint.setColor(getSpacebarTextColor(mSpacebarTextColor, textFadeFactor)); - canvas.drawText(language, width / 2, baseline - descent, paint); - } - - // Draw the spacebar icon at the bottom - if (isAutoCorrection) { - final int iconWidth = width * SPACE_LED_LENGTH_PERCENT / 100; - final int iconHeight = mAutoCorrectionSpacebarLedIcon.getIntrinsicHeight(); - int x = (width - iconWidth) / 2; - int y = height - iconHeight; - mAutoCorrectionSpacebarLedIcon.setBounds(x, y, x + iconWidth, y + iconHeight); - mAutoCorrectionSpacebarLedIcon.draw(canvas); - } else if (mSpaceIcon != null) { - final int iconWidth = mSpaceIcon.getIntrinsicWidth(); - final int iconHeight = mSpaceIcon.getIntrinsicHeight(); - int x = (width - iconWidth) / 2; - int y = height - iconHeight; - mSpaceIcon.setBounds(x, y, x + iconWidth, y + iconHeight); - mSpaceIcon.draw(canvas); - } - return buffer; - } - - @Override - public int[] getNearestKeys(int x, int y) { - // Avoid dead pixels at edges of the keyboard - return super.getNearestKeys(Math.max(0, Math.min(x, mOccupiedWidth - 1)), - Math.max(0, Math.min(y, mOccupiedHeight - 1))); - } - - private static final int[] ATTR_TEXT_SIZE = { android.R.attr.textSize }; - - public static int getTextSizeFromTheme(Theme theme, int style, int defValue) { - final TypedArray a = theme.obtainStyledAttributes(style, ATTR_TEXT_SIZE); - final int textSize = a.getDimensionPixelSize(a.getResourceId(0, 0), defValue); - a.recycle(); - return textSize; - } -} diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index 6ce3876b6..88a41579d 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -18,13 +18,17 @@ package com.android.inputmethod.keyboard; import android.content.Context; import android.content.pm.PackageManager; -import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Paint.Align; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; import android.os.Message; -import android.os.SystemClock; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; -import android.view.GestureDetector; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; @@ -38,11 +42,15 @@ import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; import com.android.inputmethod.deprecated.VoiceProxy; import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy; import com.android.inputmethod.keyboard.PointerTracker.TimerProxy; +import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; import com.android.inputmethod.latin.LatinIME; +import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; import com.android.inputmethod.latin.Utils; +import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils; +import java.util.Locale; import java.util.WeakHashMap; /** @@ -56,45 +64,66 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke SuddenJumpingTouchEventHandler.ProcessMotionEvent { private static final String TAG = LatinKeyboardView.class.getSimpleName(); - private static final boolean ENABLE_CAPSLOCK_BY_DOUBLETAP = true; + // TODO: Kill process when the usability study mode was changed. + private static final boolean ENABLE_USABILITY_STUDY_LOG = LatinImeLogger.sUsabilityStudy; - private final SuddenJumpingTouchEventHandler mTouchScreenRegulator; - - // Timing constants - private final int mKeyRepeatInterval; + /** Listener for {@link KeyboardActionListener}. */ + private KeyboardActionListener mKeyboardActionListener; - // Mini keyboard + /* Space key and its icons */ + private Key mSpaceKey; + private Drawable mSpaceIcon; + // Stuff to draw language name on spacebar. + private boolean mNeedsToDisplayLanguage; + private Locale mSpacebarLocale; + private float mSpacebarTextFadeFactor = 0.0f; + private final float mSpacebarTextRatio; + private float mSpacebarTextSize; + private final int mSpacebarTextColor; + private final int mSpacebarTextShadowColor; + // Height in space key the language name will be drawn. (proportional to space key height) + private static final float SPACEBAR_LANGUAGE_BASELINE = 0.6f; + // If the full language name needs to be smaller than this value to be drawn on space key, + // its short language name will be used instead. + private static final float MINIMUM_SCALE_OF_LANGUAGE_NAME = 0.8f; + // Stuff to draw auto correction LED on spacebar. + private boolean mAutoCorrectionSpacebarLedOn; + private final boolean mAutoCorrectionSpacebarLedEnabled; + private final Drawable mAutoCorrectionSpacebarLedIcon; + private static final int SPACE_LED_LENGTH_PERCENT = 80; + + // More keys keyboard private PopupWindow mMoreKeysWindow; private MoreKeysPanel mMoreKeysPanel; private int mMoreKeysPanelPointerTrackerId; private final WeakHashMap<Key, MoreKeysPanel> mMoreKeysPanelCache = new WeakHashMap<Key, MoreKeysPanel>(); + private final boolean mConfigShowMoreKeysKeyboardAtTouchedPoint; - /** Listener for {@link KeyboardActionListener}. */ - private KeyboardActionListener mKeyboardActionListener; - - private final boolean mHasDistinctMultitouch; - private int mOldPointerCount = 1; - private int mOldKeyIndex; + private final PointerTrackerParams mPointerTrackerParams; + private final boolean mIsSpacebarTriggeringPopupByLongPress; + private final SuddenJumpingTouchEventHandler mTouchScreenRegulator; - private final boolean mConfigShowMiniKeyboardAtTouchedPoint; protected KeyDetector mKeyDetector; + private boolean mHasDistinctMultitouch; + private int mOldPointerCount = 1; + private Key mOldKey; - // To detect double tap. - protected GestureDetector mGestureDetector; - - private final KeyTimerHandler mKeyTimerHandler = new KeyTimerHandler(this); + private final KeyTimerHandler mKeyTimerHandler; private static class KeyTimerHandler extends StaticInnerHandlerWrapper<LatinKeyboardView> implements TimerProxy { 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_DOUBLE_TAP = 3; + private static final int MSG_KEY_TYPED = 4; + private final KeyTimerParams mParams; private boolean mInKeyRepeat; - public KeyTimerHandler(LatinKeyboardView outerInstance) { + public KeyTimerHandler(LatinKeyboardView outerInstance, KeyTimerParams params) { super(outerInstance); + mParams = params; } @Override @@ -103,19 +132,27 @@ 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(tracker, mParams.mKeyRepeatInterval); break; case MSG_LONGPRESS_KEY: - keyboardView.openMiniKeyboardIfRequired(msg.arg1, tracker); + if (tracker != null) { + keyboardView.openMoreKeysKeyboardIfRequired(tracker.getKey(), tracker); + } else { + KeyboardSwitcher.getInstance().onLongPressTimeout(msg.arg1); + } break; } } + private void startKeyRepeatTimer(PointerTracker tracker, long delay) { + sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, tracker), delay); + } + @Override - public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker) { + public void startKeyRepeatTimer(PointerTracker tracker) { mInKeyRepeat = true; - sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, keyIndex, 0, tracker), delay); + startKeyRepeatTimer(tracker, mParams.mKeyRepeatStartTimeout); } public void cancelKeyRepeatTimer() { @@ -128,9 +165,49 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke } @Override - public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker) { + public void startLongPressTimer(int code) { + cancelLongPressTimer(); + final int delay; + switch (code) { + case Keyboard.CODE_SHIFT: + delay = mParams.mLongPressShiftKeyTimeout; + break; + default: + delay = 0; + break; + } + if (delay > 0) { + sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, code, 0), delay); + } + } + + @Override + public void startLongPressTimer(PointerTracker tracker) { cancelLongPressTimer(); - sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, keyIndex, 0, tracker), delay); + if (tracker != null) { + final Key key = tracker.getKey(); + final int delay; + switch (key.mCode) { + case Keyboard.CODE_SHIFT: + delay = mParams.mLongPressShiftKeyTimeout; + break; + case Keyboard.CODE_SPACE: + delay = mParams.mLongPressSpaceKeyTimeout; + break; + default: + if (KeyboardSwitcher.getInstance().isInMomentarySwitchState()) { + // We use longer timeout for sliding finger input started from the symbols + // mode key. + delay = mParams.mLongPressKeyTimeout * 3; + } else { + delay = mParams.mLongPressKeyTimeout; + } + break; + } + if (delay > 0) { + sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, tracker), delay); + } + } } @Override @@ -139,19 +216,31 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke } @Override - public void cancelKeyTimers() { - cancelKeyRepeatTimer(); - cancelLongPressTimer(); - removeMessages(MSG_IGNORE_DOUBLE_TAP); + public void startKeyTypedTimer() { + removeMessages(MSG_KEY_TYPED); + sendMessageDelayed(obtainMessage(MSG_KEY_TYPED), mParams.mIgnoreSpecialKeyTimeout); + } + + @Override + public boolean isTyping() { + return hasMessages(MSG_KEY_TYPED); } - public void startIgnoringDoubleTap() { - sendMessageDelayed(obtainMessage(MSG_IGNORE_DOUBLE_TAP), + @Override + public void startDoubleTapTimer() { + sendMessageDelayed(obtainMessage(MSG_DOUBLE_TAP), ViewConfiguration.getDoubleTapTimeout()); } - public boolean isIgnoringDoubleTap() { - return hasMessages(MSG_IGNORE_DOUBLE_TAP); + @Override + public boolean isInDoubleTapTimeout() { + return hasMessages(MSG_DOUBLE_TAP); + } + + @Override + public void cancelKeyTimers() { + cancelKeyRepeatTimer(); + cancelLongPressTimer(); } public void cancelAllMessages() { @@ -159,52 +248,64 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke } } - private class DoubleTapListener extends GestureDetector.SimpleOnGestureListener { - private boolean mProcessingShiftDoubleTapEvent = false; + public static class PointerTrackerParams { + public final boolean mSlidingKeyInputEnabled; + public final int mTouchNoiseThresholdTime; + public final float mTouchNoiseThresholdDistance; - @Override - public boolean onDoubleTap(MotionEvent firstDown) { - final Keyboard keyboard = getKeyboard(); - if (ENABLE_CAPSLOCK_BY_DOUBLETAP && keyboard instanceof LatinKeyboard - && ((LatinKeyboard) keyboard).isAlphaKeyboard()) { - final int pointerIndex = firstDown.getActionIndex(); - final int id = firstDown.getPointerId(pointerIndex); - final PointerTracker tracker = getPointerTracker(id); - // If the first down event is on shift key. - if (tracker.isOnShiftKey((int) firstDown.getX(), (int) firstDown.getY())) { - mProcessingShiftDoubleTapEvent = true; - return true; - } - } - mProcessingShiftDoubleTapEvent = false; - return false; + public static final PointerTrackerParams DEFAULT = new PointerTrackerParams(); + + private PointerTrackerParams() { + mSlidingKeyInputEnabled = false; + mTouchNoiseThresholdTime =0; + mTouchNoiseThresholdDistance = 0; } - @Override - public boolean onDoubleTapEvent(MotionEvent secondTap) { - if (mProcessingShiftDoubleTapEvent - && secondTap.getAction() == MotionEvent.ACTION_DOWN) { - final MotionEvent secondDown = secondTap; - final int pointerIndex = secondDown.getActionIndex(); - final int id = secondDown.getPointerId(pointerIndex); - final PointerTracker tracker = getPointerTracker(id); - // If the second down event is also on shift key. - if (tracker.isOnShiftKey((int) secondDown.getX(), (int) secondDown.getY())) { - // 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} . - onDoubleTapShiftKey(tracker, mKeyTimerHandler.isIgnoringDoubleTap()); - return true; - } - // Otherwise these events should not be handled as double tap. - mProcessingShiftDoubleTapEvent = false; - } - return mProcessingShiftDoubleTapEvent; + public PointerTrackerParams(TypedArray latinKeyboardViewAttr) { + mSlidingKeyInputEnabled = latinKeyboardViewAttr.getBoolean( + R.styleable.LatinKeyboardView_slidingKeyInputEnable, false); + mTouchNoiseThresholdTime = latinKeyboardViewAttr.getInt( + R.styleable.LatinKeyboardView_touchNoiseThresholdTime, 0); + mTouchNoiseThresholdDistance = latinKeyboardViewAttr.getDimension( + R.styleable.LatinKeyboardView_touchNoiseThresholdDistance, 0); + } + } + + static class KeyTimerParams { + public final int mKeyRepeatStartTimeout; + public final int mKeyRepeatInterval; + public final int mLongPressKeyTimeout; + public final int mLongPressShiftKeyTimeout; + public final int mLongPressSpaceKeyTimeout; + public final int mIgnoreSpecialKeyTimeout; + + KeyTimerParams() { + mKeyRepeatStartTimeout = 0; + mKeyRepeatInterval = 0; + mLongPressKeyTimeout = 0; + mLongPressShiftKeyTimeout = 0; + mLongPressSpaceKeyTimeout = 0; + mIgnoreSpecialKeyTimeout = 0; + } + + public KeyTimerParams(TypedArray latinKeyboardViewAttr) { + mKeyRepeatStartTimeout = latinKeyboardViewAttr.getInt( + R.styleable.LatinKeyboardView_keyRepeatStartTimeout, 0); + mKeyRepeatInterval = latinKeyboardViewAttr.getInt( + R.styleable.LatinKeyboardView_keyRepeatInterval, 0); + mLongPressKeyTimeout = latinKeyboardViewAttr.getInt( + R.styleable.LatinKeyboardView_longPressKeyTimeout, 0); + mLongPressShiftKeyTimeout = latinKeyboardViewAttr.getInt( + R.styleable.LatinKeyboardView_longPressShiftKeyTimeout, 0); + mLongPressSpaceKeyTimeout = latinKeyboardViewAttr.getInt( + R.styleable.LatinKeyboardView_longPressSpaceKeyTimeout, 0); + mIgnoreSpecialKeyTimeout = latinKeyboardViewAttr.getInt( + R.styleable.LatinKeyboardView_ignoreSpecialKeyTimeout, 0); } } public LatinKeyboardView(Context context, AttributeSet attrs) { - this(context, attrs, R.attr.keyboardViewStyle); + this(context, attrs, R.attr.latinKeyboardViewStyle); } public LatinKeyboardView(Context context, AttributeSet attrs, int defStyle) { @@ -212,27 +313,36 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke mTouchScreenRegulator = new SuddenJumpingTouchEventHandler(getContext(), this); - final Resources res = getResources(); - mConfigShowMiniKeyboardAtTouchedPoint = res.getBoolean( - R.bool.config_show_mini_keyboard_at_touched_point); - final float keyHysteresisDistance = res.getDimension(R.dimen.key_hysteresis_distance); - mKeyDetector = new KeyDetector(keyHysteresisDistance); - - final boolean ignoreMultitouch = true; - mGestureDetector = new GestureDetector( - getContext(), new DoubleTapListener(), null, ignoreMultitouch); - mGestureDetector.setIsLongpressEnabled(false); - mHasDistinctMultitouch = context.getPackageManager() .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT); - mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval); - PointerTracker.init(mHasDistinctMultitouch, getContext()); - } + PointerTracker.init(mHasDistinctMultitouch); + + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.LatinKeyboardView, defStyle, R.style.LatinKeyboardView); + mAutoCorrectionSpacebarLedEnabled = a.getBoolean( + R.styleable.LatinKeyboardView_autoCorrectionSpacebarLedEnabled, false); + mAutoCorrectionSpacebarLedIcon = a.getDrawable( + R.styleable.LatinKeyboardView_autoCorrectionSpacebarLedIcon); + mSpacebarTextRatio = a.getFraction(R.styleable.LatinKeyboardView_spacebarTextRatio, + 1000, 1000, 1) / 1000.0f; + mSpacebarTextColor = a.getColor(R.styleable.LatinKeyboardView_spacebarTextColor, 0); + mSpacebarTextShadowColor = a.getColor( + R.styleable.LatinKeyboardView_spacebarTextShadowColor, 0); + + final KeyTimerParams keyTimerParams = new KeyTimerParams(a); + mPointerTrackerParams = new PointerTrackerParams(a); + mIsSpacebarTriggeringPopupByLongPress = (keyTimerParams.mLongPressSpaceKeyTimeout > 0); + + final float keyHysteresisDistance = a.getDimension( + R.styleable.LatinKeyboardView_keyHysteresisDistance, 0); + mKeyDetector = new KeyDetector(keyHysteresisDistance); + mKeyTimerHandler = new KeyTimerHandler(this, keyTimerParams); + mConfigShowMoreKeysKeyboardAtTouchedPoint = a.getBoolean( + R.styleable.LatinKeyboardView_showMoreKeysKeyboardAtTouchedPoint, false); + a.recycle(); - public void startIgnoringDoubleTap() { - if (ENABLE_CAPSLOCK_BY_DOUBLETAP) - mKeyTimerHandler.startIgnoringDoubleTap(); + PointerTracker.setParameters(mPointerTrackerParams); } public void setKeyboardActionListener(KeyboardActionListener listener) { @@ -264,20 +374,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. @@ -296,6 +392,12 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke PointerTracker.setKeyDetector(mKeyDetector); mTouchScreenRegulator.setKeyboard(keyboard); mMoreKeysPanelCache.clear(); + + mSpaceKey = keyboard.getKey(Keyboard.CODE_SPACE); + mSpaceIcon = keyboard.mIconsSet.getIconDrawable(KeyboardIconsSet.ICON_SPACE); + final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap; + mSpacebarTextSize = keyHeight * mSpacebarTextRatio; + mSpacebarLocale = keyboard.mId.mLocale; } /** @@ -306,6 +408,10 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke return mHasDistinctMultitouch; } + public void setDistinctMultitouch(boolean hasDistinctMultitouch) { + mHasDistinctMultitouch = hasDistinctMultitouch; + } + /** * When enabled, calls to {@link KeyboardActionListener#onCodeInput} will include key * codes for adjacent keys. When disabled, only the primary key code will be @@ -329,7 +435,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke super.cancelAllMessages(); } - private boolean openMiniKeyboardIfRequired(int keyIndex, PointerTracker tracker) { + private boolean openMoreKeysKeyboardIfRequired(Key parentKey, PointerTracker tracker) { // Check if we have a popup layout specified first. if (mMoreKeysLayout == 0) { return false; @@ -338,22 +444,11 @@ 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); } - private void onDoubleTapShiftKey(@SuppressWarnings("unused") PointerTracker tracker, - final boolean ignore) { - // 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); - } - // This default implementation returns a more keys panel. protected MoreKeysPanel onCreateMoreKeysPanel(Key parentKey) { if (parentKey.mMoreKeys == null) @@ -363,28 +458,19 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke if (container == null) throw new NullPointerException(); - final MiniKeyboardView miniKeyboardView = - (MiniKeyboardView)container.findViewById(R.id.mini_keyboard_view); + final MoreKeysKeyboardView moreKeysKeyboardView = + (MoreKeysKeyboardView)container.findViewById(R.id.more_keys_keyboard_view); final Keyboard parentKeyboard = getKeyboard(); - final Keyboard miniKeyboard = new MiniKeyboard.Builder( + final Keyboard moreKeysKeyboard = new MoreKeysKeyboard.Builder( this, parentKeyboard.mMoreKeysTemplate, parentKey, parentKeyboard).build(); - miniKeyboardView.setKeyboard(miniKeyboard); + moreKeysKeyboardView.setKeyboard(moreKeysKeyboard); container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - return miniKeyboardView; - } - - public void setSpacebarTextFadeFactor(float fadeFactor, LatinKeyboard oldKeyboard) { - final Keyboard keyboard = getKeyboard(); - // We should not set text fade factor to the keyboard which does not display the language on - // its spacebar. - if (keyboard instanceof LatinKeyboard && keyboard == oldKeyboard) { - ((LatinKeyboard)keyboard).setSpacebarTextFadeFactor(fadeFactor, this); - } + return moreKeysKeyboardView; } /** - * Called when a key is long pressed. By default this will open mini keyboard associated + * Called when a key is long pressed. By default this will open more keys keyboard associated * with this key. * @param parentKey the key that was long pressed * @param tracker the pointer tracker which pressed the parent key @@ -394,48 +480,37 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke protected boolean onLongPress(Key parentKey, PointerTracker tracker) { final int primaryCode = parentKey.mCode; final Keyboard keyboard = getKeyboard(); - if (keyboard instanceof LatinKeyboard) { - final LatinKeyboard latinKeyboard = (LatinKeyboard) keyboard; - if (primaryCode == Keyboard.CODE_DIGIT0 && latinKeyboard.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()) { - tracker.onLongPressed(); - invokeCodeInput(Keyboard.CODE_CAPSLOCK); - invokeReleaseKey(primaryCode); - return true; - } + if (primaryCode == Keyboard.CODE_DIGIT0 && keyboard.mId.isPhoneKeyboard()) { + tracker.onLongPressed(); + // Long pressing on 0 in phone number keypad gives you a '+'. + invokeCodeInput(Keyboard.CODE_PLUS); + invokeReleaseKey(primaryCode); + KeyboardSwitcher.getInstance().hapticAndAudioFeedback(primaryCode); + return true; } - if (primaryCode == Keyboard.CODE_SETTINGS || primaryCode == Keyboard.CODE_SPACE) { - // Both long pressing settings key and space key invoke IME switcher dialog. + if (primaryCode == Keyboard.CODE_SPACE) { + // Long pressing the space key invokes IME switcher dialog. if (invokeCustomRequest(LatinIME.CODE_SHOW_INPUT_METHOD_PICKER)) { tracker.onLongPressed(); invokeReleaseKey(primaryCode); return true; - } else { - return openMoreKeysPanel(parentKey, tracker); } - } else { - return openMoreKeysPanel(parentKey, tracker); } + return openMoreKeysPanel(parentKey, tracker); } private boolean invokeCustomRequest(int code) { - return getKeyboardActionListener().onCustomRequest(code); + return mKeyboardActionListener.onCustomRequest(code); } private void invokeCodeInput(int primaryCode) { - getKeyboardActionListener().onCodeInput(primaryCode, null, + mKeyboardActionListener.onCodeInput(primaryCode, null, KeyboardActionListener.NOT_A_TOUCH_COORDINATE, KeyboardActionListener.NOT_A_TOUCH_COORDINATE); } private void invokeReleaseKey(int primaryCode) { - getKeyboardActionListener().onRelease(primaryCode, false); + mKeyboardActionListener.onReleaseKey(primaryCode, false); } private boolean openMoreKeysPanel(Key parentKey, PointerTracker tracker) { @@ -449,30 +524,24 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke if (mMoreKeysWindow == null) { mMoreKeysWindow = new PopupWindow(getContext()); mMoreKeysWindow.setBackgroundDrawable(null); - mMoreKeysWindow.setAnimationStyle(R.style.MiniKeyboardAnimation); + mMoreKeysWindow.setAnimationStyle(R.style.MoreKeysKeyboardAnimation); } mMoreKeysPanel = moreKeysPanel; mMoreKeysPanelPointerTrackerId = tracker.mPointerId; final Keyboard keyboard = getKeyboard(); - moreKeysPanel.setShifted(keyboard.isShiftedOrShiftLocked()); - final int pointX = (mConfigShowMiniKeyboardAtTouchedPoint) ? tracker.getLastX() + final int pointX = (mConfigShowMoreKeysKeyboardAtTouchedPoint) ? tracker.getLastX() : parentKey.mX + parentKey.mWidth / 2; final int pointY = parentKey.mY - keyboard.mVerticalGap; moreKeysPanel.showMoreKeysPanel( - this, this, pointX, pointY, mMoreKeysWindow, getKeyboardActionListener()); + this, this, pointX, pointY, mMoreKeysWindow, mKeyboardActionListener); 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; } - private PointerTracker getPointerTracker(final int id) { - return PointerTracker.getPointerTracker(id, this); - } - public boolean isInSlidingKeyInput() { if (mMoreKeysPanel != null) { return true; @@ -508,14 +577,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke return true; } - // Gesture detector must be enabled only when mini-keyboard is not on the screen. - if (mMoreKeysPanel == null && mGestureDetector != null - && mGestureDetector.onTouchEvent(me)) { - PointerTracker.dismissAllKeyPreviews(); - mKeyTimerHandler.cancelKeyTimers(); - return true; - } - final long eventTime = me.getEventTime(); final int index = me.getActionIndex(); final int id = me.getPointerId(index); @@ -527,9 +588,37 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke x = (int)me.getX(index); y = (int)me.getY(index); } + if (ENABLE_USABILITY_STUDY_LOG) { + final String eventTag; + switch (action) { + case MotionEvent.ACTION_UP: + eventTag = "[Up]"; + break; + case MotionEvent.ACTION_DOWN: + eventTag = "[Down]"; + break; + case MotionEvent.ACTION_POINTER_UP: + eventTag = "[PointerUp]"; + break; + case MotionEvent.ACTION_POINTER_DOWN: + eventTag = "[PointerDown]"; + break; + case MotionEvent.ACTION_MOVE: // Skip this as being logged below + eventTag = ""; + break; + default: + eventTag = "[Action" + action + "]"; + break; + } + if (!TextUtils.isEmpty(eventTag)) { + UsabilityStudyLogUtils.getInstance().write( + eventTag + eventTime + "," + id + "," + x + "," + y + "," + + me.getSize(index) + "," + me.getPressure(index)); + } + } if (mKeyTimerHandler.isInKeyRepeat()) { - final PointerTracker tracker = getPointerTracker(id); + final PointerTracker tracker = PointerTracker.getPointerTracker(id, this); // Key repeating timer will be canceled if 2 or more keys are in action, and current // event (UP or DOWN) is non-modifier key. if (pointerCount > 1 && !tracker.isModifier()) { @@ -543,13 +632,13 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke // multi-touch panel. if (nonDistinctMultitouch) { // Use only main (id=0) pointer tracker. - PointerTracker tracker = getPointerTracker(0); + final PointerTracker tracker = PointerTracker.getPointerTracker(0, this); if (pointerCount == 1 && oldPointerCount == 2) { // 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 +648,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); @@ -572,7 +661,8 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke if (action == MotionEvent.ACTION_MOVE) { for (int i = 0; i < pointerCount; i++) { - final PointerTracker tracker = getPointerTracker(me.getPointerId(i)); + final PointerTracker tracker = PointerTracker.getPointerTracker( + me.getPointerId(i), this); final int px, py; if (mMoreKeysPanel != null && tracker.mPointerId == mMoreKeysPanelPointerTrackerId) { @@ -583,9 +673,15 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke py = (int)me.getY(i); } tracker.onMoveEvent(px, py, eventTime); + if (ENABLE_USABILITY_STUDY_LOG) { + UsabilityStudyLogUtils.getInstance().write("[Move]" + eventTime + "," + + me.getPointerId(i) + "," + px + "," + py + "," + + me.getSize(i) + "," + me.getPressure(i)); + } } } else { - getPointerTracker(id).processMotionEvent(action, x, y, eventTime, this); + final PointerTracker tracker = PointerTracker.getPointerTracker(id, this); + tracker.processMotionEvent(action, x, y, eventTime, this); } return true; @@ -637,9 +733,8 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke @Override public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { - final PointerTracker tracker = getPointerTracker(0); return AccessibleKeyboardViewProxy.getInstance().dispatchPopulateAccessibilityEvent( - event, tracker) || super.dispatchPopulateAccessibilityEvent(event); + event) || super.dispatchPopulateAccessibilityEvent(event); } return super.dispatchPopulateAccessibilityEvent(event); @@ -656,11 +751,133 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke */ public boolean dispatchHoverEvent(MotionEvent event) { if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { - final PointerTracker tracker = getPointerTracker(0); + final PointerTracker tracker = PointerTracker.getPointerTracker(0, this); return AccessibleKeyboardViewProxy.getInstance().dispatchHoverEvent(event, tracker); } // Reflection doesn't support calling superclass methods. return false; } + + public void updateShortcutKey(boolean available) { + final Keyboard keyboard = getKeyboard(); + if (keyboard == null) return; + final Key shortcutKey = keyboard.getKey(Keyboard.CODE_SHORTCUT); + if (shortcutKey == null) return; + shortcutKey.setEnabled(available); + invalidateKey(shortcutKey); + } + + public void updateSpacebar(float fadeFactor, boolean needsToDisplayLanguage) { + mSpacebarTextFadeFactor = fadeFactor; + mNeedsToDisplayLanguage = needsToDisplayLanguage; + invalidateKey(mSpaceKey); + } + + public void updateAutoCorrectionState(boolean isAutoCorrection) { + if (!mAutoCorrectionSpacebarLedEnabled) return; + mAutoCorrectionSpacebarLedOn = isAutoCorrection; + invalidateKey(mSpaceKey); + } + + @Override + protected void onDrawKeyTopVisuals(Key key, Canvas canvas, Paint paint, KeyDrawParams params) { + super.onDrawKeyTopVisuals(key, canvas, paint, params); + + if (key.mCode == Keyboard.CODE_SPACE) { + drawSpacebar(key, canvas, paint); + + // Whether space key needs to show the "..." popup hint for special purposes + if (mIsSpacebarTriggeringPopupByLongPress + && Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) { + drawKeyPopupHint(key, canvas, paint, params); + } + } + } + + private static int getSpacebarTextColor(int color, float fadeFactor) { + final int newColor = Color.argb((int)(Color.alpha(color) * fadeFactor), + Color.red(color), Color.green(color), Color.blue(color)); + return newColor; + } + + // Compute width of text with specified text size using paint. + private int getTextWidth(Paint paint, String text, float textSize) { + paint.setTextSize(textSize); + return (int)getLabelWidth(text, paint); + } + + // Layout locale language name on spacebar. + private String layoutLanguageOnSpacebar(Paint paint, Locale locale, int width, + float origTextSize) { + paint.setTextAlign(Align.CENTER); + paint.setTypeface(Typeface.DEFAULT); + // Estimate appropriate language name text size to fit in maxTextWidth. + String language = Utils.getFullDisplayName(locale, true); + int textWidth = getTextWidth(paint, language, origTextSize); + // Assuming text width and text size are proportional to each other. + float textSize = origTextSize * Math.min(width / textWidth, 1.0f); + // allow variable text size + textWidth = getTextWidth(paint, language, textSize); + // If text size goes too small or text does not fit, use middle or short name + final boolean useMiddleName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME) + || (textWidth > width); + + final boolean useShortName; + if (useMiddleName) { + language = Utils.getMiddleDisplayLanguage(locale); + textWidth = getTextWidth(paint, language, origTextSize); + textSize = origTextSize * Math.min(width / textWidth, 1.0f); + useShortName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME) + || (textWidth > width); + } else { + useShortName = false; + } + + if (useShortName) { + language = Utils.getShortDisplayLanguage(locale); + textWidth = getTextWidth(paint, language, origTextSize); + textSize = origTextSize * Math.min(width / textWidth, 1.0f); + } + paint.setTextSize(textSize); + + return language; + } + + private void drawSpacebar(Key key, Canvas canvas, Paint paint) { + final int width = key.mWidth; + final int height = mSpaceIcon != null ? mSpaceIcon.getIntrinsicHeight() : key.mHeight; + + // If application locales are explicitly selected. + if (mNeedsToDisplayLanguage) { + final String language = layoutLanguageOnSpacebar(paint, mSpacebarLocale, width, + mSpacebarTextSize); + // Draw language text with shadow + // In case there is no space icon, we will place the language text at the center of + // spacebar. + final float descent = paint.descent(); + final float textHeight = -paint.ascent() + descent; + final float baseline = (mSpaceIcon != null) ? height * SPACEBAR_LANGUAGE_BASELINE + : height / 2 + textHeight / 2; + paint.setColor(getSpacebarTextColor(mSpacebarTextShadowColor, mSpacebarTextFadeFactor)); + canvas.drawText(language, width / 2, baseline - descent - 1, paint); + paint.setColor(getSpacebarTextColor(mSpacebarTextColor, mSpacebarTextFadeFactor)); + canvas.drawText(language, width / 2, baseline - descent, paint); + } + + // Draw the spacebar icon at the bottom + if (mAutoCorrectionSpacebarLedOn) { + final int iconWidth = width * SPACE_LED_LENGTH_PERCENT / 100; + final int iconHeight = mAutoCorrectionSpacebarLedIcon.getIntrinsicHeight(); + int x = (width - iconWidth) / 2; + int y = height - iconHeight; + drawIcon(canvas, mAutoCorrectionSpacebarLedIcon, x, y, iconWidth, iconHeight); + } else if (mSpaceIcon != null) { + final int iconWidth = mSpaceIcon.getIntrinsicWidth(); + final int iconHeight = mSpaceIcon.getIntrinsicHeight(); + int x = (width - iconWidth) / 2; + int y = height - iconHeight; + drawIcon(canvas, mSpaceIcon, x, y, iconWidth, iconHeight); + } + } } 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/MiniKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java index ac9290bfd..1597b1ebb 100644 --- a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java @@ -18,15 +18,13 @@ package com.android.inputmethod.keyboard; import android.graphics.Paint; -import com.android.inputmethod.keyboard.internal.KeyboardBuilder; -import com.android.inputmethod.keyboard.internal.KeyboardParams; -import com.android.inputmethod.keyboard.internal.MoreKeySpecParser; +import com.android.inputmethod.keyboard.internal.KeySpecParser; import com.android.inputmethod.latin.R; -public class MiniKeyboard extends Keyboard { +public class MoreKeysKeyboard extends Keyboard { private final int mDefaultKeyCoordX; - private MiniKeyboard(Builder.MiniKeyboardParams params) { + MoreKeysKeyboard(Builder.MoreKeysKeyboardParams params) { super(params); mDefaultKeyCoordX = params.getDefaultKeyCoordX() + params.mDefaultKeyWidth / 2; } @@ -35,21 +33,21 @@ public class MiniKeyboard extends Keyboard { return mDefaultKeyCoordX; } - public static class Builder extends KeyboardBuilder<Builder.MiniKeyboardParams> { - private final CharSequence[] mMoreKeys; + public static class Builder extends Keyboard.Builder<Builder.MoreKeysKeyboardParams> { + private final String[] mMoreKeys; - public static class MiniKeyboardParams extends KeyboardParams { + public static class MoreKeysKeyboardParams extends Keyboard.Params { /* package */int mTopRowAdjustment; public int mNumRows; public int mNumColumns; public int mLeftKeys; public int mRightKeys; // includes default key. - public MiniKeyboardParams() { + public MoreKeysKeyboardParams() { super(); } - /* package for test */MiniKeyboardParams(int numKeys, int maxColumns, int keyWidth, + /* package for test */MoreKeysKeyboardParams(int numKeys, int maxColumns, int keyWidth, int rowHeight, int coordXInParent, int parentKeyboardWidth) { super(); setParameters(numKeys, maxColumns, keyWidth, rowHeight, coordXInParent, @@ -57,21 +55,21 @@ public class MiniKeyboard extends Keyboard { } /** - * Set keyboard parameters of mini keyboard. + * Set keyboard parameters of more keys keyboard. * - * @param numKeys number of keys in this mini keyboard. - * @param maxColumns number of maximum columns of this mini keyboard. - * @param keyWidth mini keyboard key width in pixel, including horizontal gap. - * @param rowHeight mini keyboard row height in pixel, including vertical gap. - * @param coordXInParent coordinate x of the popup key in parent keyboard. + * @param numKeys number of keys in this more keys keyboard. + * @param maxColumns number of maximum columns of this more keys keyboard. + * @param keyWidth more keys keyboard key width in pixel, including horizontal gap. + * @param rowHeight more keys keyboard row height in pixel, including vertical gap. + * @param coordXInParent coordinate x of the key preview in parent keyboard. * @param parentKeyboardWidth parent keyboard width in pixel. */ public void setParameters(int numKeys, int maxColumns, int keyWidth, int rowHeight, int coordXInParent, int parentKeyboardWidth) { if (parentKeyboardWidth / keyWidth < maxColumns) { throw new IllegalArgumentException( - "Keyboard is too small to hold mini keyboard: " + parentKeyboardWidth - + " " + keyWidth + " " + maxColumns); + "Keyboard is too small to hold more keys keyboard: " + + parentKeyboardWidth + " " + keyWidth + " " + maxColumns); } mDefaultKeyWidth = keyWidth; mDefaultRowHeight = rowHeight; @@ -83,29 +81,29 @@ public class MiniKeyboard extends Keyboard { final int numLeftKeys = (numColumns - 1) / 2; final int numRightKeys = numColumns - numLeftKeys; // including default key. + // Maximum number of keys we can layout both side of the parent key final int maxLeftKeys = coordXInParent / keyWidth; - final int maxRightKeys = Math.max(1, (parentKeyboardWidth - coordXInParent) - / keyWidth); + final int maxRightKeys = (parentKeyboardWidth - coordXInParent) / keyWidth; int leftKeys, rightKeys; if (numLeftKeys > maxLeftKeys) { leftKeys = maxLeftKeys; - rightKeys = numColumns - maxLeftKeys; - } else if (numRightKeys > maxRightKeys) { - leftKeys = numColumns - maxRightKeys; - rightKeys = maxRightKeys; + rightKeys = numColumns - leftKeys; + } else if (numRightKeys > maxRightKeys + 1) { + rightKeys = maxRightKeys + 1; // include default key + leftKeys = numColumns - rightKeys; } else { leftKeys = numLeftKeys; rightKeys = numRightKeys; } - // Shift right if the left edge of mini keyboard is on the edge of parent keyboard - // unless the parent key is on the left edge. - if (leftKeys * keyWidth >= coordXInParent && leftKeys > 0) { + // If the left keys fill the left side of the parent key, entire more keys keyboard + // should be shifted to the right unless the parent key is on the left edge. + if (maxLeftKeys == leftKeys && leftKeys > 0) { leftKeys--; rightKeys++; } - // Shift left if the right edge of mini keyboard is on the edge of parent keyboard - // unless the parent key is on the right edge. - if (rightKeys * keyWidth + coordXInParent >= parentKeyboardWidth && rightKeys > 1) { + // If the right keys fill the right side of the parent key, entire more keys + // should be shifted to the left unless the parent key is on the right edge. + if (maxRightKeys == rightKeys - 1 && rightKeys > 1) { leftKeys++; rightKeys--; } @@ -113,8 +111,7 @@ public class MiniKeyboard extends Keyboard { mRightKeys = rightKeys; // Centering of the top row. - final boolean onEdge = (leftKeys == 0 || rightKeys == 1); - if (numRows < 2 || onEdge || getTopRowEmptySlots(numKeys, numColumns) % 2 == 0) { + if (numRows < 2 || getTopRowEmptySlots(numKeys, numColumns) % 2 == 0) { mTopRowAdjustment = 0; } else if (mLeftKeys < mRightKeys - 1) { mTopRowAdjustment = 1; @@ -206,20 +203,20 @@ public class MiniKeyboard extends Keyboard { } public Builder(KeyboardView view, int xmlId, Key parentKey, Keyboard parentKeyboard) { - super(view.getContext(), new MiniKeyboardParams()); - load(parentKeyboard.mId.cloneWithNewXml(mResources.getResourceEntryName(xmlId), xmlId)); + super(view.getContext(), new MoreKeysKeyboardParams()); + load(xmlId, parentKeyboard.mId); - // TODO: Mini keyboard's vertical gap is currently calculated heuristically. + // TODO: More keys keyboard's vertical gap is currently calculated heuristically. // Should revise the algorithm. mParams.mVerticalGap = parentKeyboard.mVerticalGap / 2; - mParams.mIsRtlKeyboard = parentKeyboard.mIsRtlKeyboard; mMoreKeys = parentKey.mMoreKeys; final int previewWidth = view.mKeyPreviewDrawParams.mPreviewBackgroundWidth; final int previewHeight = view.mKeyPreviewDrawParams.mPreviewBackgroundHeight; final int width, height; - // Use pre-computed width and height if these values are available and mini keyboard - // has only one key to mitigate visual flicker between key preview and mini keyboard. + // Use pre-computed width and height if these values are available and more keys + // keyboard has only one key to mitigate visual flicker between key preview and more + // keys keyboard. if (view.isKeyPreviewPopupEnabled() && mMoreKeys.length == 1 && previewWidth > 0 && previewHeight > 0) { width = previewWidth; @@ -229,19 +226,17 @@ public class MiniKeyboard extends Keyboard { height = parentKeyboard.mMostCommonKeyHeight; } mParams.setParameters(mMoreKeys.length, parentKey.mMaxMoreKeysColumn, width, height, - parentKey.mX + (mParams.mDefaultKeyWidth - width) / 2, view.getMeasuredWidth()); + parentKey.mX + parentKey.mWidth / 2, view.getMeasuredWidth()); } - private static int getMaxKeyWidth(KeyboardView view, CharSequence[] moreKeys, - int minKeyWidth) { + private static int getMaxKeyWidth(KeyboardView view, String[] moreKeys, int minKeyWidth) { final int padding = (int) view.getContext().getResources() - .getDimension(R.dimen.mini_keyboard_key_horizontal_padding); + .getDimension(R.dimen.more_keys_keyboard_key_horizontal_padding); Paint paint = null; int maxWidth = minKeyWidth; - for (CharSequence moreKeySpec : moreKeys) { - final CharSequence label = MoreKeySpecParser.getLabel(moreKeySpec.toString()); - // If the label is single letter, minKeyWidth is enough to hold - // the label. + for (String moreKeySpec : moreKeys) { + final String label = KeySpecParser.getLabel(moreKeySpec); + // If the label is single letter, minKeyWidth is enough to hold the label. if (label != null && label.length() > 1) { if (paint == null) { paint = new Paint(); @@ -257,17 +252,17 @@ public class MiniKeyboard extends Keyboard { } @Override - public MiniKeyboard build() { - final MiniKeyboardParams params = mParams; + public MoreKeysKeyboard build() { + final MoreKeysKeyboardParams params = mParams; for (int n = 0; n < mMoreKeys.length; n++) { - final String moreKeySpec = mMoreKeys[n].toString(); + final String moreKeySpec = mMoreKeys[n]; final int row = n / params.mNumColumns; final Key key = new Key(mResources, params, moreKeySpec, params.getX(n, row), params.getY(row), params.mDefaultKeyWidth, params.mDefaultRowHeight); params.markAsEdgeKey(key, row); params.onAddKey(key); } - return new MiniKeyboard(params); + return new MoreKeysKeyboard(params); } } } diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java index f2c5b7b49..b030dd95a 100644 --- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java @@ -28,10 +28,10 @@ import com.android.inputmethod.keyboard.PointerTracker.TimerProxy; import com.android.inputmethod.latin.R; /** - * A view that renders a virtual {@link MiniKeyboard}. It handles rendering of keys and detecting - * key presses and touch movements. + * A view that renders a virtual {@link MoreKeysKeyboard}. It handles rendering of keys and + * detecting key presses and touch movements. */ -public class MiniKeyboardView extends KeyboardView implements MoreKeysPanel { +public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel { private final int[] mCoordinates = new int[2]; private final KeyDetector mKeyDetector; @@ -43,7 +43,7 @@ public class MiniKeyboardView extends KeyboardView implements MoreKeysPanel { private static final TimerProxy EMPTY_TIMER_PROXY = new TimerProxy.Adapter(); - private final KeyboardActionListener mMiniKeyboardListener = + private final KeyboardActionListener mMoreKeysKeyboardListener = new KeyboardActionListener.Adapter() { @Override public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) { @@ -61,25 +61,26 @@ public class MiniKeyboardView extends KeyboardView implements MoreKeysPanel { } @Override - public void onPress(int primaryCode, boolean withSliding) { - mListener.onPress(primaryCode, withSliding); + public void onPressKey(int primaryCode) { + mListener.onPressKey(primaryCode); } + @Override - public void onRelease(int primaryCode, boolean withSliding) { - mListener.onRelease(primaryCode, withSliding); + public void onReleaseKey(int primaryCode, boolean withSliding) { + mListener.onReleaseKey(primaryCode, withSliding); } }; - public MiniKeyboardView(Context context, AttributeSet attrs) { - this(context, attrs, R.attr.miniKeyboardViewStyle); + public MoreKeysKeyboardView(Context context, AttributeSet attrs) { + this(context, attrs, R.attr.moreKeysKeyboardViewStyle); } - public MiniKeyboardView(Context context, AttributeSet attrs, int defStyle) { + public MoreKeysKeyboardView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); final Resources res = context.getResources(); mKeyDetector = new MoreKeysDetector( - res.getDimension(R.dimen.mini_keyboard_slide_allowance)); + res.getDimension(R.dimen.more_keys_keyboard_slide_allowance)); setKeyPreviewPopupEnabled(false, 0); } @@ -109,7 +110,7 @@ public class MiniKeyboardView extends KeyboardView implements MoreKeysPanel { @Override public KeyboardActionListener getKeyboardActionListener() { - return mMiniKeyboardListener; + return mMoreKeysKeyboardListener; } @Override @@ -124,32 +125,24 @@ public class MiniKeyboardView extends KeyboardView implements MoreKeysPanel { @Override public void setKeyPreviewPopupEnabled(boolean previewEnabled, int delay) { - // Mini keyboard needs no pop-up key preview displayed, so we pass always false with a + // More keys keyboard needs no pop-up key preview displayed, so we pass always false with a // delay of 0. The delay does not matter actually since the popup is not shown anyway. super.setKeyPreviewPopupEnabled(false, 0); } @Override - public void setShifted(boolean shifted) { - final Keyboard keyboard = getKeyboard(); - if (keyboard.setShifted(shifted)) { - invalidateAllKeys(); - } - } - - @Override public void showMoreKeysPanel(View parentView, Controller controller, int pointX, int pointY, PopupWindow window, KeyboardActionListener listener) { mController = controller; mListener = listener; final View container = (View)getParent(); - final MiniKeyboard miniKeyboard = (MiniKeyboard)getKeyboard(); + final MoreKeysKeyboard moreKeysKeyboard = (MoreKeysKeyboard)getKeyboard(); parentView.getLocationInWindow(mCoordinates); - final int miniKeyboardLeft = pointX - miniKeyboard.getDefaultCoordX() + final int moreKeysKeyboardLeft = pointX - moreKeysKeyboard.getDefaultCoordX() + parentView.getPaddingLeft(); - final int x = wrapUp(Math.max(0, Math.min(miniKeyboardLeft, - parentView.getWidth() - miniKeyboard.mOccupiedWidth)) + final int x = wrapUp(Math.max(0, Math.min(moreKeysKeyboardLeft, + parentView.getWidth() - moreKeysKeyboard.mOccupiedWidth)) - container.getPaddingLeft() + mCoordinates[0], container.getMeasuredWidth(), 0, parentView.getWidth()); final int y = pointY diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java b/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java index 6314a99db..f9a196d24 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java @@ -24,8 +24,6 @@ public interface MoreKeysPanel extends PointerTracker.KeyEventHandler { public boolean dismissMoreKeysPanel(); } - public void setShifted(boolean shifted); - /** * Show more keys panel. * diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 198e06aab..110f7f6ae 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -16,19 +16,17 @@ 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; import com.android.inputmethod.keyboard.internal.PointerTrackerQueue; import com.android.inputmethod.latin.LatinImeLogger; -import com.android.inputmethod.latin.R; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; +import java.util.Set; public class PointerTracker { private static final String TAG = PointerTracker.class.getSimpleName(); @@ -67,37 +65,46 @@ 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 cancelShowKeyPreview(PointerTracker tracker); + public void showKeyPreview(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(); + public boolean isTyping(); + public void startKeyRepeatTimer(PointerTracker tracker); + public void startLongPressTimer(PointerTracker tracker); + public void startLongPressTimer(int code); public void cancelLongPressTimer(); + public void startDoubleTapTimer(); + public boolean isInDoubleTapTimeout(); public void cancelKeyTimers(); public static class Adapter implements TimerProxy { @Override - public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker) {} + public void startKeyTypedTimer() {} @Override - public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker) {} + public boolean isTyping() { return false; } + @Override + public void startKeyRepeatTimer(PointerTracker tracker) {} + @Override + public void startLongPressTimer(PointerTracker tracker) {} + @Override + public void startLongPressTimer(int code) {} @Override public void cancelLongPressTimer() {} @Override + public void startDoubleTapTimer() {} + @Override + public boolean isInDoubleTapTimeout() { return false; } + @Override public void cancelKeyTimers() {} } } private static KeyboardSwitcher sKeyboardSwitcher; - private static boolean sConfigSlidingKeyInputEnabled; - // Timing constants - private static int sDelayBeforeKeyRepeatStart; - private static int sLongPressKeyTimeout; - private static int sLongPressShiftKeyTimeout; - private static int sLongPressSpaceKeyTimeout; - private static int sTouchNoiseThresholdMillis; + // Parameters for pointer handling. + private static LatinKeyboardView.PointerTrackerParams sParams; private static int sTouchNoiseThresholdDistanceSquared; private static final List<PointerTracker> sTrackers = new ArrayList<PointerTracker>(); @@ -111,7 +118,7 @@ public class PointerTracker { private KeyboardActionListener mListener = EMPTY_LISTENER; private Keyboard mKeyboard; - private List<Key> mKeys; + private Set<Key> mKeys; private int mKeyQuarterWidthSquared; private final TextView mKeyPreviewText; @@ -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; @@ -154,27 +161,23 @@ public class PointerTracker { private static final KeyboardActionListener EMPTY_LISTENER = new KeyboardActionListener.Adapter(); - public static void init(boolean hasDistinctMultitouch, Context context) { + public static void init(boolean hasDistinctMultitouch) { if (hasDistinctMultitouch) { sPointerTrackerQueue = new PointerTrackerQueue(); } else { sPointerTrackerQueue = null; } - final Resources res = context.getResources(); - sConfigSlidingKeyInputEnabled = res.getBoolean(R.bool.config_sliding_key_input_enabled); - sDelayBeforeKeyRepeatStart = res.getInteger(R.integer.config_delay_before_key_repeat_start); - 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); - sTouchNoiseThresholdMillis = res.getInteger(R.integer.config_touch_noise_threshold_millis); - final float touchNoiseThresholdDistance = res.getDimension( - R.dimen.config_touch_noise_threshold_distance); - sTouchNoiseThresholdDistanceSquared = (int)( - touchNoiseThresholdDistance * touchNoiseThresholdDistance); + setParameters(LatinKeyboardView.PointerTrackerParams.DEFAULT); sKeyboardSwitcher = KeyboardSwitcher.getInstance(); } + public static void setParameters(LatinKeyboardView.PointerTrackerParams params) { + sParams = params; + sTouchNoiseThresholdDistanceSquared = (int)( + params.mTouchNoiseThresholdDistance * params.mTouchNoiseThresholdDistance); + } + public static PointerTracker getPointerTracker(final int id, KeyEventHandler handler) { final List<PointerTracker> trackers = sTrackers; @@ -207,7 +210,7 @@ public class PointerTracker { public static void dismissAllKeyPreviews() { for (final PointerTracker tracker : sTrackers) { - tracker.setReleasedKeyGraphics(tracker.mKeyIndex); + tracker.setReleasedKeyGraphics(tracker.mCurrentKey); } } @@ -227,15 +230,18 @@ 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) + private boolean callListenerOnPressAndCheckKeyboardLayoutChange(Key key) { + final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); + if (DEBUG_LISTENER) { + Log.d(TAG, "onPress : " + KeyDetector.printableCode(key) + + " ignoreModifier=" + ignoreModifierKey + + " enabled=" + key.isEnabled()); + } + if (ignoreModifierKey) { return false; + } if (key.isEnabled()) { - mListener.onPress(key.mCode, withSliding); + mListener.onPressKey(key.mCode); final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged; mKeyboardLayoutHasBeenChanged = false; return keyboardLayoutHasBeenChanged; @@ -246,35 +252,45 @@ 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 (DEBUG_LISTENER) { + Log.d(TAG, "onCodeInput: " + Keyboard.printableCode(code) + " text=" + key.mOutputText + + " 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_OUTPUT_TEXT) { + mListener.onTextInput(key.mOutputText); + } else if (code != Keyboard.CODE_UNSPECIFIED) { + mListener.onCodeInput(code, keyCodes, x, y); + } + if (!key.altCodeWhileTyping() && !key.isModifier()) { + mTimerProxy.startKeyTypedTimer(); + } + } } // 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 : " + Keyboard.printableCode(primaryCode) + + " sliding=" + withSliding + " ignoreModifier=" + ignoreModifierKey + + " enabled="+ key.isEnabled()); + } + if (ignoreModifierKey) { return; - if (key.isEnabled()) - mListener.onRelease(primaryCode, withSliding); + } + if (key.isEnabled()) { + mListener.onReleaseKey(primaryCode, withSliding); + } } private void callListenerOnCancelInput() { @@ -295,71 +311,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)); + return mCurrentKey != null && mCurrentKey.isModifier(); } - public boolean isOnShiftKey(int x, int y) { - final Key key = getKey(mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null)); - return key != null && key.mCode == Keyboard.CODE_SHIFT; + public Key getKeyOn(int x, int y) { + return mKeyDetector.getKeyAndNearbyCodes(x, y, null); } - public int getKeyIndexOn(int x, int y) { - return mKeyDetector.getKeyIndexAndNearbyCodes(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 +388,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); } @@ -432,7 +446,7 @@ public class PointerTracker { setKeyDetectorInner(handler.getKeyDetector()); // Naive up-to-down noise filter. final long deltaT = eventTime - mUpTime; - if (deltaT < sTouchNoiseThresholdMillis) { + if (deltaT < sParams.mTouchNoiseThresholdTime) { final int dx = x - mLastX; final int dy = y - mLastY; final int distanceSquared = (dx * dx + dy * dy); @@ -447,7 +461,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 +473,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 = sParams.mSlidingKeyInputEnabled + || (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)) { + 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 +513,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)) { + 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)) { + 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 +562,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 +589,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); @@ -594,7 +613,6 @@ public class PointerTracker { private void onUpEventInternal(int x, int y, long eventTime) { mTimerProxy.cancelKeyTimers(); - mDrawingProxy.cancelShowKeyPreview(this); mIsInSlidingKeyInput = false; final int keyX, keyY; if (isMajorEnoughMoveToBeOnNewKey(x, y, onMoveKey(x, y))) { @@ -605,8 +623,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 +632,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); @@ -647,8 +665,7 @@ public class PointerTracker { private void onCancelEventInternal() { mTimerProxy.cancelKeyTimers(); - mDrawingProxy.cancelShowKeyPreview(this); - setReleasedKeyGraphics(mKeyIndex); + setReleasedKeyGraphics(mCurrentKey); mIsInSlidingKeyInput = false; if (mIsShowingMoreKeysPanel) { mDrawingProxy.dismissMoreKeysPanel(); @@ -656,108 +673,71 @@ 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(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); - if (key == null) return; - if (key.mCode == Keyboard.CODE_SHIFT) { - if (sLongPressShiftKeyTimeout > 0) { - mTimerProxy.startLongPressTimer(sLongPressShiftKeyTimeout, keyIndex, this); - } - } else if (key.mCode == Keyboard.CODE_SPACE) { - if (sLongPressSpaceKeyTimeout > 0) { - mTimerProxy.startLongPressTimer(sLongPressSpaceKeyTimeout, keyIndex, this); - } - } else if (key.hasUppercaseLetter() && mKeyboard.isManualTemporaryUpperCase()) { - // We need not start long press timer on the key which has manual temporary upper case - // code defined and the keyboard is in manual temporary upper case mode. - 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); - } else { - mTimerProxy.startLongPressTimer(sLongPressKeyTimeout, keyIndex, this); + private void startLongPressTimer(Key key) { + if (key != null && key.isLongPressEnabled()) { + mTimerProxy.startLongPressTimer(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); + + // 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..41e7ef435 100644 --- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java +++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java @@ -18,19 +18,22 @@ package com.android.inputmethod.keyboard; import android.graphics.Rect; -import com.android.inputmethod.keyboard.internal.KeyboardParams.TouchPositionCorrection; +import com.android.inputmethod.keyboard.Keyboard.Params.TouchPositionCorrection; import com.android.inputmethod.latin.Utils; import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Set; public class ProximityInfo { public static final int MAX_PROXIMITY_CHARS_SIZE = 16; /** Number of key widths from current touch point to search for nearest keys. */ private static float SEARCH_DISTANCE = 1.2f; - private static final int[] EMPTY_INT_ARRAY = new int[0]; + private static final Key[] EMPTY_KEY_ARRAY = new Key[0]; private final int mKeyHeight; private final int mGridWidth; @@ -41,10 +44,11 @@ public class ProximityInfo { // TODO: Find a proper name for mKeyboardMinWidth private final int mKeyboardMinWidth; private final int mKeyboardHeight; - private final int[][] mGridNeighbors; + private final Key[][] mGridNeighbors; ProximityInfo(int gridWidth, int gridHeight, int minWidth, int height, int keyWidth, - int keyHeight, List<Key> keys, TouchPositionCorrection touchPositionCorrection) { + int keyHeight, Set<Key> keys, TouchPositionCorrection touchPositionCorrection, + Map<Integer, List<Integer>> additionalProximityChars) { mGridWidth = gridWidth; mGridHeight = gridHeight; mGridSize = mGridWidth * mGridHeight; @@ -53,49 +57,51 @@ public class ProximityInfo { mKeyboardMinWidth = minWidth; mKeyboardHeight = height; mKeyHeight = keyHeight; - mGridNeighbors = new int[mGridSize][]; + mGridNeighbors = new Key[mGridSize][]; if (minWidth == 0 || height == 0) { - // No proximity required. Keyboard might be mini keyboard. + // No proximity required. Keyboard might be more keys keyboard. return; } - computeNearestNeighbors(keyWidth, keys, touchPositionCorrection); + computeNearestNeighbors(keyWidth, keys, touchPositionCorrection, additionalProximityChars); } public static ProximityInfo createDummyProximityInfo() { - return new ProximityInfo(1, 1, 1, 1, 1, 1, Collections.<Key>emptyList(), null); + return new ProximityInfo(1, 1, 1, 1, 1, 1, Collections.<Key> emptySet(), + null, Collections.<Integer, List<Integer>> emptyMap()); } - public static ProximityInfo createSpellCheckerProximityInfo() { + public static ProximityInfo createSpellCheckerProximityInfo(final int[] proximity) { final ProximityInfo spellCheckerProximityInfo = createDummyProximityInfo(); spellCheckerProximityInfo.mNativeProximityInfo = spellCheckerProximityInfo.setProximityInfoNative( - SpellCheckerProximityInfo.ROW_SIZE, - 480, 300, 10, 3, SpellCheckerProximityInfo.PROXIMITY, - 0, null, null, null, null, null, null, null, null); + SpellCheckerProximityInfo.ROW_SIZE, 480, 300, 11, 3, proximity, 0, + null, null, null, null, null, null, null, null); 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 final void setProximityInfo(int[][] gridNeighborKeyIndexes, int keyboardWidth, - int keyboardHeight, List<Key> keys, + private native void releaseProximityInfoNative(long nativeProximityInfo); + + private final void setProximityInfo(Key[][] gridNeighborKeys, int keyboardWidth, + int keyboardHeight, Set<Key> keys, TouchPositionCorrection touchPositionCorrection) { - int[] proximityCharsArray = new int[mGridSize * MAX_PROXIMITY_CHARS_SIZE]; + final int[] proximityCharsArray = new int[mGridSize * MAX_PROXIMITY_CHARS_SIZE]; Arrays.fill(proximityCharsArray, KeyDetector.NOT_A_CODE); for (int i = 0; i < mGridSize; ++i) { - final int proximityCharsLength = gridNeighborKeyIndexes[i].length; + final int proximityCharsLength = gridNeighborKeys[i].length; for (int j = 0; j < proximityCharsLength; ++j) { proximityCharsArray[i * MAX_PROXIMITY_CHARS_SIZE + j] = - keys.get(gridNeighborKeyIndexes[i][j]).mCode; + gridNeighborKeys[i][j].mCode; } } final int keyCount = keys.size(); @@ -104,25 +110,45 @@ public class ProximityInfo { final int[] keyWidths = new int[keyCount]; final int[] keyHeights = new int[keyCount]; final int[] keyCharCodes = new int[keyCount]; - for (int i = 0; i < keyCount; ++i) { - final Key key = keys.get(i); + final float[] sweetSpotCenterXs; + final float[] sweetSpotCenterYs; + final float[] sweetSpotRadii; + final boolean calculateSweetSpotParams; + if (touchPositionCorrection != null && touchPositionCorrection.isValid()) { + sweetSpotCenterXs = new float[keyCount]; + sweetSpotCenterYs = new float[keyCount]; + sweetSpotRadii = new float[keyCount]; + calculateSweetSpotParams = true; + } else { + sweetSpotCenterXs = sweetSpotCenterYs = sweetSpotRadii = null; + calculateSweetSpotParams = false; + } + + int i = 0; + for (final Key key : keys) { keyXCoordinates[i] = key.mX; keyYCoordinates[i] = key.mY; keyWidths[i] = key.mWidth; keyHeights[i] = key.mHeight; keyCharCodes[i] = key.mCode; - } - - float[] sweetSpotCenterXs = null; - float[] sweetSpotCenterYs = null; - float[] sweetSpotRadii = null; - - if (touchPositionCorrection != null && touchPositionCorrection.isValid()) { - sweetSpotCenterXs = new float[keyCount]; - sweetSpotCenterYs = new float[keyCount]; - sweetSpotRadii = new float[keyCount]; - calculateSweetSpot(keys, touchPositionCorrection, - sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii); + if (calculateSweetSpotParams) { + final Rect hitBox = key.mHitBox; + final int row = hitBox.top / mKeyHeight; + if (row < touchPositionCorrection.mRadii.length) { + final float hitBoxCenterX = (hitBox.left + hitBox.right) * 0.5f; + final float hitBoxCenterY = (hitBox.top + hitBox.bottom) * 0.5f; + final float hitBoxWidth = hitBox.right - hitBox.left; + final float hitBoxHeight = hitBox.bottom - hitBox.top; + final float x = touchPositionCorrection.mXs[row]; + final float y = touchPositionCorrection.mYs[row]; + final float radius = touchPositionCorrection.mRadii[row]; + sweetSpotCenterXs[i] = hitBoxCenterX + x * hitBoxWidth; + sweetSpotCenterYs[i] = hitBoxCenterY + y * hitBoxHeight; + sweetSpotRadii[i] = radius * (float) Math.sqrt( + hitBoxWidth * hitBoxWidth + hitBoxHeight * hitBoxHeight); + } + } + i++; } mNativeProximityInfo = setProximityInfoNative(MAX_PROXIMITY_CHARS_SIZE, @@ -131,33 +157,7 @@ public class ProximityInfo { sweetSpotCenterXs, sweetSpotCenterYs, sweetSpotRadii); } - private void calculateSweetSpot(List<Key> keys, TouchPositionCorrection touchPositionCorrection, - float[] sweetSpotCenterXs, float[] sweetSpotCenterYs, float[] sweetSpotRadii) { - final int keyCount = keys.size(); - final float[] xs = touchPositionCorrection.mXs; - final float[] ys = touchPositionCorrection.mYs; - final float[] radii = touchPositionCorrection.mRadii; - for (int i = 0; i < keyCount; ++i) { - final Key key = keys.get(i); - final Rect hitBox = key.mHitBox; - final int row = hitBox.top / mKeyHeight; - if (row < radii.length) { - final float hitBoxCenterX = (hitBox.left + hitBox.right) * 0.5f; - final float hitBoxCenterY = (hitBox.top + hitBox.bottom) * 0.5f; - final float hitBoxWidth = hitBox.right - hitBox.left; - final float hitBoxHeight = hitBox.bottom - hitBox.top; - final float x = xs[row]; - final float y = ys[row]; - final float radius = radii[row]; - sweetSpotCenterXs[i] = hitBoxCenterX + x * hitBoxWidth; - sweetSpotCenterYs[i] = hitBoxCenterY + y * hitBoxHeight; - sweetSpotRadii[i] = radius - * (float)Math.sqrt(hitBoxWidth * hitBoxWidth + hitBoxHeight * hitBoxHeight); - } - } - } - - public int getNativeProximityInfo() { + public long getNativeProximityInfo() { return mNativeProximityInfo; } @@ -173,12 +173,17 @@ public class ProximityInfo { } } - private void computeNearestNeighbors(int defaultWidth, List<Key> keys, - TouchPositionCorrection touchPositionCorrection) { + private void computeNearestNeighbors(int defaultWidth, Set<Key> keys, + TouchPositionCorrection touchPositionCorrection, + Map<Integer, List<Integer>> additionalProximityChars) { + final Map<Integer, Key> keyCodeMap = new HashMap<Integer, Key>(); + for (final Key key : keys) { + keyCodeMap.put(key.mCode, key); + } final int thresholdBase = (int) (defaultWidth * SEARCH_DISTANCE); final int threshold = thresholdBase * thresholdBase; // Round-up so we don't have any pixels outside the grid - final int[] indices = new int[keys.size()]; + final Key[] neighborKeys = new Key[keys.size()]; final int gridWidth = mGridWidth * mCellWidth; final int gridHeight = mGridHeight * mCellHeight; for (int x = 0; x < gridWidth; x += mCellWidth) { @@ -186,31 +191,51 @@ public class ProximityInfo { final int centerX = x + mCellWidth / 2; final int centerY = y + mCellHeight / 2; int count = 0; - for (int i = 0; i < keys.size(); i++) { - final Key key = keys.get(i); + for (final Key key : keys) { if (key.isSpacer()) continue; - if (key.squaredDistanceToEdge(centerX, centerY) < threshold) - indices[count++] = i; + if (key.squaredDistanceToEdge(centerX, centerY) < threshold) { + neighborKeys[count++] = key; + } + } + int currentCodesSize = count; + for (int i = 0; i < currentCodesSize; ++i) { + final int c = neighborKeys[i].mCode; + final List<Integer> additionalChars = additionalProximityChars.get(c); + if (additionalChars == null || additionalChars.size() == 0) { + continue; + } + for (int j = 0; j < additionalChars.size(); ++j) { + final int additionalChar = additionalChars.get(j); + boolean contains = false; + for (int k = 0; k < count; ++k) { + if(additionalChar == neighborKeys[k].mCode) { + contains = true; + break; + } + } + if (!contains) { + neighborKeys[count++] = keyCodeMap.get(additionalChar); + } + } } - final int[] cell = new int[count]; - System.arraycopy(indices, 0, cell, 0, count); - mGridNeighbors[(y / mCellHeight) * mGridWidth + (x / mCellWidth)] = cell; + mGridNeighbors[(y / mCellHeight) * mGridWidth + (x / mCellWidth)] = + Arrays.copyOfRange(neighborKeys, 0, count); } } setProximityInfo(mGridNeighbors, mKeyboardMinWidth, mKeyboardHeight, keys, touchPositionCorrection); } - public int[] getNearestKeys(int x, int y) { + public Key[] getNearestKeys(int x, int y) { if (mGridNeighbors == null) { - return EMPTY_INT_ARRAY; + return EMPTY_KEY_ARRAY; } if (x >= 0 && x < mKeyboardMinWidth && y >= 0 && y < mKeyboardHeight) { - int index = (y / mCellHeight) * mGridWidth + (x / mCellWidth); + int index = (y / mCellHeight) * mGridWidth + (x / mCellWidth); if (index < mGridSize) { return mGridNeighbors[index]; } } - return EMPTY_INT_ARRAY; + return EMPTY_KEY_ARRAY; } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java b/java/src/com/android/inputmethod/keyboard/internal/AlphabetShiftState.java index 28a53cedc..5712df1fc 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/AlphabetShiftState.java @@ -18,29 +18,27 @@ package com.android.inputmethod.keyboard.internal; import android.util.Log; -import com.android.inputmethod.keyboard.KeyboardSwitcher; +public class AlphabetShiftState { + private static final String TAG = AlphabetShiftState.class.getSimpleName(); + private static final boolean DEBUG = false; -public class KeyboardShiftState { - private static final String TAG = KeyboardShiftState.class.getSimpleName(); - private static final boolean DEBUG = KeyboardSwitcher.DEBUG_STATE; - - private static final int NORMAL = 0; + private static final int UNSHIFTED = 0; private static final int MANUAL_SHIFTED = 1; private static final int MANUAL_SHIFTED_FROM_AUTO = 2; - private static final int AUTO_SHIFTED = 3; + private static final int AUTOMATIC_SHIFTED = 3; private static final int SHIFT_LOCKED = 4; private static final int SHIFT_LOCK_SHIFTED = 5; - private int mState = NORMAL; + private int mState = UNSHIFTED; - public boolean setShifted(boolean newShiftState) { + public void setShifted(boolean newShiftState) { final int oldState = mState; if (newShiftState) { switch (oldState) { - case NORMAL: + case UNSHIFTED: mState = MANUAL_SHIFTED; break; - case AUTO_SHIFTED: + case AUTOMATIC_SHIFTED: mState = MANUAL_SHIFTED_FROM_AUTO; break; case SHIFT_LOCKED: @@ -51,8 +49,8 @@ public class KeyboardShiftState { switch (oldState) { case MANUAL_SHIFTED: case MANUAL_SHIFTED_FROM_AUTO: - case AUTO_SHIFTED: - mState = NORMAL; + case AUTOMATIC_SHIFTED: + mState = UNSHIFTED; break; case SHIFT_LOCK_SHIFTED: mState = SHIFT_LOCKED; @@ -61,42 +59,36 @@ public class KeyboardShiftState { } if (DEBUG) Log.d(TAG, "setShifted(" + newShiftState + "): " + toString(oldState) + " > " + this); - return mState != oldState; } public void setShiftLocked(boolean newShiftLockState) { final int oldState = mState; if (newShiftLockState) { switch (oldState) { - case NORMAL: + case UNSHIFTED: case MANUAL_SHIFTED: case MANUAL_SHIFTED_FROM_AUTO: - case AUTO_SHIFTED: + case AUTOMATIC_SHIFTED: mState = SHIFT_LOCKED; break; } } else { - switch (oldState) { - case SHIFT_LOCKED: - case SHIFT_LOCK_SHIFTED: - mState = NORMAL; - break; - } + mState = UNSHIFTED; } if (DEBUG) Log.d(TAG, "setShiftLocked(" + newShiftLockState + "): " + toString(oldState) + " > " + this); } - public void setAutomaticTemporaryUpperCase() { + public void setAutomaticShifted() { final int oldState = mState; - mState = AUTO_SHIFTED; + mState = AUTOMATIC_SHIFTED; if (DEBUG) - Log.d(TAG, "setAutomaticTemporaryUpperCase: " + toString(oldState) + " > " + this); + Log.d(TAG, "setAutomaticShifted: " + toString(oldState) + " > " + this); } public boolean isShiftedOrShiftLocked() { - return mState != NORMAL; + return mState != UNSHIFTED; } public boolean isShiftLocked() { @@ -107,16 +99,16 @@ public class KeyboardShiftState { return mState == SHIFT_LOCK_SHIFTED; } - public boolean isAutomaticTemporaryUpperCase() { - return mState == AUTO_SHIFTED; + public boolean isAutomaticShifted() { + return mState == AUTOMATIC_SHIFTED; } - public boolean isManualTemporaryUpperCase() { + public boolean isManualShifted() { return mState == MANUAL_SHIFTED || mState == MANUAL_SHIFTED_FROM_AUTO || mState == SHIFT_LOCK_SHIFTED; } - public boolean isManualTemporaryUpperCaseFromAuto() { + public boolean isManualShiftedFromAutomaticShifted() { return mState == MANUAL_SHIFTED_FROM_AUTO; } @@ -127,13 +119,13 @@ public class KeyboardShiftState { private static String toString(int state) { switch (state) { - case NORMAL: return "NORMAL"; + case UNSHIFTED: return "UNSHIFTED"; case MANUAL_SHIFTED: return "MANUAL_SHIFTED"; case MANUAL_SHIFTED_FROM_AUTO: return "MANUAL_SHIFTED_FROM_AUTO"; - case AUTO_SHIFTED: return "AUTO_SHIFTED"; + case AUTOMATIC_SHIFTED: return "AUTOMATIC_SHIFTED"; case SHIFT_LOCKED: return "SHIFT_LOCKED"; case SHIFT_LOCK_SHIFTED: return "SHIFT_LOCK_SHIFTED"; - default: return "UKNOWN"; + default: return "UNKNOWN"; } } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java new file mode 100644 index 000000000..1626a140b --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java @@ -0,0 +1,394 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.keyboard.internal; + +import android.content.res.Resources; +import android.text.TextUtils; + +import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.latin.LatinImeLogger; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.Utils; + +import java.util.ArrayList; +import java.util.Arrays; + +/** + * String parser of moreKeys attribute of Key. + * The string is comma separated texts each of which represents one "more key". + * - String resource can be embedded into specification @string/name. This is done before parsing + * comma. + * Each "more key" specification is one of the following: + * - A single letter (Letter) + * - Label optionally followed by keyOutputText or code (keyLabel|keyOutputText). + * - Icon followed by keyOutputText or code (@icon/icon_name|@integer/key_code) + * Special character, comma ',' backslash '\', and bar '|' can be escaped by '\' character. + * Note that the character '@' and '\' are also parsed by XML parser and CSV parser as well. + * See {@link KeyboardIconsSet} about icon_name. + */ +public class KeySpecParser { + private static final boolean DEBUG = LatinImeLogger.sDBG; + + private static final int MAX_STRING_REFERENCE_INDIRECTION = 10; + + // Constants for parsing. + private static int COMMA = ','; + private static final char ESCAPE_CHAR = '\\'; + private static final char PREFIX_AT = '@'; + private static final char SUFFIX_SLASH = '/'; + private static final String PREFIX_STRING = PREFIX_AT + "string" + SUFFIX_SLASH; + private static final char LABEL_END = '|'; + private static final String PREFIX_ICON = PREFIX_AT + "icon" + SUFFIX_SLASH; + private static final String PREFIX_CODE = PREFIX_AT + "integer" + SUFFIX_SLASH; + private static final String ADDITIONAL_MORE_KEY_MARKER = "%"; + + private KeySpecParser() { + // Intentional empty constructor for utility class. + } + + private static boolean hasIcon(String moreKeySpec) { + if (moreKeySpec.startsWith(PREFIX_ICON)) { + final int end = indexOfLabelEnd(moreKeySpec, 0); + if (end > 0) { + return true; + } + throw new KeySpecParserError("outputText or code not specified: " + moreKeySpec); + } + return false; + } + + private static boolean hasCode(String moreKeySpec) { + final int end = indexOfLabelEnd(moreKeySpec, 0); + if (end > 0 && end + 1 < moreKeySpec.length() + && moreKeySpec.substring(end + 1).startsWith(PREFIX_CODE)) { + return true; + } + return false; + } + + private static String parseEscape(String text) { + if (text.indexOf(ESCAPE_CHAR) < 0) { + return text; + } + final int length = text.length(); + final StringBuilder sb = new StringBuilder(); + for (int pos = 0; pos < length; pos++) { + final char c = text.charAt(pos); + if (c == ESCAPE_CHAR && pos + 1 < length) { + // Skip escape char + pos++; + sb.append(text.charAt(pos)); + } else { + sb.append(c); + } + } + return sb.toString(); + } + + private static int indexOfLabelEnd(String moreKeySpec, int start) { + if (moreKeySpec.indexOf(ESCAPE_CHAR, start) < 0) { + final int end = moreKeySpec.indexOf(LABEL_END, start); + if (end == 0) { + throw new KeySpecParserError(LABEL_END + " at " + start + ": " + moreKeySpec); + } + return end; + } + final int length = moreKeySpec.length(); + for (int pos = start; pos < length; pos++) { + final char c = moreKeySpec.charAt(pos); + if (c == ESCAPE_CHAR && pos + 1 < length) { + // Skip escape char + pos++; + } else if (c == LABEL_END) { + return pos; + } + } + return -1; + } + + public static String getLabel(String moreKeySpec) { + if (hasIcon(moreKeySpec)) { + return null; + } + final int end = indexOfLabelEnd(moreKeySpec, 0); + final String label = (end > 0) ? parseEscape(moreKeySpec.substring(0, end)) + : parseEscape(moreKeySpec); + if (TextUtils.isEmpty(label)) { + throw new KeySpecParserError("Empty label: " + moreKeySpec); + } + return label; + } + + private static String getOutputTextInternal(String moreKeySpec) { + final int end = indexOfLabelEnd(moreKeySpec, 0); + if (end <= 0) { + return null; + } + if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) { + throw new KeySpecParserError("Multiple " + LABEL_END + ": " + moreKeySpec); + } + return parseEscape(moreKeySpec.substring(end + /* LABEL_END */1)); + } + + public static String getOutputText(String moreKeySpec) { + if (hasCode(moreKeySpec)) { + return null; + } + final String outputText = getOutputTextInternal(moreKeySpec); + if (outputText != null) { + if (Utils.codePointCount(outputText) == 1) { + // If output text is one code point, it should be treated as a code. + // See {@link #getCode(Resources, String)}. + return null; + } + if (!TextUtils.isEmpty(outputText)) { + return outputText; + } + throw new KeySpecParserError("Empty outputText: " + moreKeySpec); + } + final String label = getLabel(moreKeySpec); + if (label == null) { + throw new KeySpecParserError("Empty label: " + moreKeySpec); + } + // Code is automatically generated for one letter label. See {@link getCode()}. + return (Utils.codePointCount(label) == 1) ? null : label; + } + + public static int getCode(Resources res, String moreKeySpec) { + if (hasCode(moreKeySpec)) { + final int end = indexOfLabelEnd(moreKeySpec, 0); + if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) { + throw new KeySpecParserError("Multiple " + LABEL_END + ": " + moreKeySpec); + } + final int resId = getResourceId(res, + moreKeySpec.substring(end + /* LABEL_END */1 + /* PREFIX_AT */1), + R.string.english_ime_name); + final int code = res.getInteger(resId); + return code; + } + final String outputText = getOutputTextInternal(moreKeySpec); + if (outputText != null) { + // If output text is one code point, it should be treated as a code. + // See {@link #getOutputText(String)}. + if (Utils.codePointCount(outputText) == 1) { + return outputText.codePointAt(0); + } + return Keyboard.CODE_OUTPUT_TEXT; + } + final String label = getLabel(moreKeySpec); + // Code is automatically generated for one letter label. + if (Utils.codePointCount(label) == 1) { + return label.codePointAt(0); + } + return Keyboard.CODE_OUTPUT_TEXT; + } + + public static int getIconId(String moreKeySpec) { + if (hasIcon(moreKeySpec)) { + final int end = moreKeySpec.indexOf(LABEL_END, PREFIX_ICON.length()); + final String name = moreKeySpec.substring(PREFIX_ICON.length(), end); + return KeyboardIconsSet.getIconId(name); + } + return KeyboardIconsSet.ICON_UNDEFINED; + } + + public static String[] insertAddtionalMoreKeys(String[] moreKeys, String[] additionalMoreKeys) { + final int moreKeysCount = (moreKeys != null) ? moreKeys.length : 0; + final int additionalCount = (additionalMoreKeys != null) ? additionalMoreKeys.length : 0; + ArrayList<String> out = null; + int additionalIndex = 0; + for (int moreKeyIndex = 0; moreKeyIndex < moreKeysCount; moreKeyIndex++) { + final String moreKeySpec = moreKeys[moreKeyIndex]; + if (moreKeySpec.equals(ADDITIONAL_MORE_KEY_MARKER)) { + if (additionalIndex < additionalCount) { + // Replace '%' marker with additional more key specification. + final String additionalMoreKey = additionalMoreKeys[additionalIndex]; + if (out != null) { + out.add(additionalMoreKey); + } else { + moreKeys[moreKeyIndex] = additionalMoreKey; + } + additionalIndex++; + } else { + // Filter out excessive '%' marker. + if (out == null) { + out = new ArrayList<String>(moreKeyIndex); + for (int i = 0; i < moreKeyIndex; i++) { + out.add(moreKeys[i]); + } + } + } + } else { + if (out != null) { + out.add(moreKeySpec); + } + } + } + if (additionalCount > 0 && additionalIndex == 0) { + // No '%' marker is found in more keys. + // Insert all additional more keys to the head of more keys. + if (DEBUG && out != null) { + throw new RuntimeException("Internal logic error:" + + " moreKeys=" + Arrays.toString(moreKeys) + + " additionalMoreKeys=" + Arrays.toString(additionalMoreKeys)); + } + out = new ArrayList<String>(additionalCount + moreKeysCount); + for (int i = additionalIndex; i < additionalCount; i++) { + out.add(additionalMoreKeys[i]); + } + for (int i = 0; i < moreKeysCount; i++) { + out.add(moreKeys[i]); + } + } else if (additionalIndex < additionalCount) { + // The number of '%' markers are less than additional more keys. + // Append remained additional more keys to the tail of more keys. + if (DEBUG && out != null) { + throw new RuntimeException("Internal logic error:" + + " moreKeys=" + Arrays.toString(moreKeys) + + " additionalMoreKeys=" + Arrays.toString(additionalMoreKeys)); + } + out = new ArrayList<String>(moreKeysCount); + for (int i = 0; i < moreKeysCount; i++) { + out.add(moreKeys[i]); + } + for (int i = additionalIndex; i < additionalCount; i++) { + out.add(additionalMoreKeys[additionalIndex]); + } + } + if (out != null) { + return out.size() > 0 ? out.toArray(new String[out.size()]) : null; + } else { + return moreKeys; + } + } + + @SuppressWarnings("serial") + public static class KeySpecParserError extends RuntimeException { + public KeySpecParserError(String message) { + super(message); + } + } + + private static int getResourceId(Resources res, String name, int packageNameResId) { + String packageName = res.getResourcePackageName(packageNameResId); + int resId = res.getIdentifier(name, null, packageName); + if (resId == 0) { + throw new RuntimeException("Unknown resource: " + name); + } + return resId; + } + + private static String resolveStringResource(String rawText, Resources res, + int packageNameResId) { + int level = 0; + String text = rawText; + StringBuilder sb; + do { + level++; + if (level >= MAX_STRING_REFERENCE_INDIRECTION) { + throw new RuntimeException("too many @string/resource indirection: " + text); + } + + final int size = text.length(); + if (size < PREFIX_STRING.length()) { + return text; + } + + sb = null; + for (int pos = 0; pos < size; pos++) { + final char c = text.charAt(pos); + if (c == PREFIX_AT && text.startsWith(PREFIX_STRING, pos)) { + if (sb == null) { + sb = new StringBuilder(text.substring(0, pos)); + } + final int end = searchResourceNameEnd(text, pos + PREFIX_STRING.length()); + final String resName = text.substring(pos + 1, end); + final int resId = getResourceId(res, resName, packageNameResId); + sb.append(res.getString(resId)); + pos = end - 1; + } else if (c == ESCAPE_CHAR) { + if (sb != null) { + // Append both escape character and escaped character. + sb.append(text.substring(pos, Math.min(pos + 2, size))); + } + pos++; + } else if (sb != null) { + sb.append(c); + } + } + + if (sb != null) { + text = sb.toString(); + } + } while (sb != null); + + return text; + } + + private static int searchResourceNameEnd(String text, int start) { + final int size = text.length(); + for (int pos = start; pos < size; pos++) { + final char c = text.charAt(pos); + // String resource name should be consisted of [a-z_0-9]. + if ((c >= 'a' && c <= 'z') || c == '_' || (c >= '0' && c <= '9')) { + continue; + } + return pos; + } + return size; + } + + public static String[] parseCsvString(String rawText, Resources res, int packageNameResId) { + final String text = resolveStringResource(rawText, res, packageNameResId); + final int size = text.length(); + if (size == 0) { + return null; + } + if (Utils.codePointCount(text) == 1) { + return text.codePointAt(0) == COMMA ? null : new String[] { text }; + } + + ArrayList<String> list = null; + int start = 0; + for (int pos = 0; pos < size; pos++) { + final char c = text.charAt(pos); + if (c == COMMA) { + // Skip empty entry. + if (pos - start > 0) { + if (list == null) { + list = new ArrayList<String>(); + } + list.add(text.substring(start, pos)); + } + // Skip comma + start = pos + 1; + } else if (c == ESCAPE_CHAR) { + // Skip escape character and escaped character. + pos++; + } + } + final String remain = (size - start > 0) ? text.substring(start) : null; + if (list == null) { + return remain != null ? new String[] { remain } : null; + } else { + if (remain != null) { + list.add(remain); + } + return list.toArray(new String[list.size()]); + } + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java index b385b7a04..12a9c51f2 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java @@ -19,16 +19,17 @@ package com.android.inputmethod.keyboard.internal; import android.content.res.TypedArray; import android.util.Log; -import com.android.inputmethod.keyboard.internal.KeyboardBuilder.ParseException; +import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.XmlParseUtils; import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; -import java.util.ArrayList; import java.util.HashMap; public class KeyStyles { - private static final String TAG = "KeyStyles"; + private static final String TAG = KeyStyles.class.getSimpleName(); private static final boolean DEBUG = false; private final HashMap<String, DeclaredKeyStyle> mStyles = @@ -36,26 +37,21 @@ public class KeyStyles { private static final KeyStyle EMPTY_KEY_STYLE = new EmptyKeyStyle(); public interface KeyStyle { - public CharSequence[] getTextArray(TypedArray a, int index); - public CharSequence getText(TypedArray a, int index); + public String[] getStringArray(TypedArray a, int index); + public String getString(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); + public int getFlag(TypedArray a, int index); } - /* package */ static class EmptyKeyStyle implements KeyStyle { - private EmptyKeyStyle() { - // Nothing to do. - } - + static class EmptyKeyStyle implements KeyStyle { @Override - public CharSequence[] getTextArray(TypedArray a, int index) { - return parseTextArray(a, index); + public String[] getStringArray(TypedArray a, int index) { + return KeyStyles.parseStringArray(a, index); } @Override - public CharSequence getText(TypedArray a, int index) { - return a.getText(index); + public String getString(TypedArray a, int index) { + return a.getString(index); } @Override @@ -64,170 +60,127 @@ public class KeyStyles { } @Override - public int getFlag(TypedArray a, int index, int defaultValue) { - 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; - final CharSequence text = a.getText(index); - return parseCsvText(text); - } - - /* package */ static CharSequence[] parseCsvText(CharSequence text) { - final int size = text.length(); - if (size == 0) return null; - if (size == 1) return new CharSequence[] { text }; - final StringBuilder sb = new StringBuilder(); - ArrayList<CharSequence> list = null; - int start = 0; - for (int pos = 0; pos < size; pos++) { - final char c = text.charAt(pos); - if (c == ',') { - if (list == null) list = new ArrayList<CharSequence>(); - if (sb.length() == 0) { - list.add(text.subSequence(start, pos)); - } else { - list.add(sb.toString()); - sb.setLength(0); - } - start = pos + 1; - continue; - } else if (c == '\\') { - if (start == pos) { - // Skip escape character at the beginning of the value. - start++; - pos++; - } else { - if (start < pos && sb.length() == 0) - sb.append(text.subSequence(start, pos)); - pos++; - if (pos < size) - sb.append(text.charAt(pos)); - } - } else if (sb.length() > 0) { - sb.append(c); - } - } - if (list == null) { - return new CharSequence[] { sb.length() > 0 ? sb : text.subSequence(start, size) }; - } else { - list.add(sb.length() > 0 ? sb : text.subSequence(start, size)); - return list.toArray(new CharSequence[list.size()]); - } + public int getFlag(TypedArray a, int index) { + return a.getInt(index, 0); } } - private static class DeclaredKeyStyle extends EmptyKeyStyle { - private final HashMap<Integer, Object> mAttributes = new HashMap<Integer, Object>(); + static class DeclaredKeyStyle implements KeyStyle { + private final HashMap<Integer, Object> mStyleAttributes = new HashMap<Integer, Object>(); @Override - public CharSequence[] getTextArray(TypedArray a, int index) { - return a.hasValue(index) - ? super.getTextArray(a, index) : (CharSequence[])mAttributes.get(index); + public String[] getStringArray(TypedArray a, int index) { + if (a.hasValue(index)) { + return parseStringArray(a, index); + } + return (String[])mStyleAttributes.get(index); } @Override - public CharSequence getText(TypedArray a, int index) { - return a.hasValue(index) - ? super.getText(a, index) : (CharSequence)mAttributes.get(index); + public String getString(TypedArray a, int index) { + if (a.hasValue(index)) { + return a.getString(index); + } + return (String)mStyleAttributes.get(index); } @Override public int getInt(TypedArray a, int index, int defaultValue) { - final Integer value = (Integer)mAttributes.get(index); - return super.getInt(a, index, (value != null) ? value : defaultValue); - } - - @Override - public int getFlag(TypedArray a, int index, int defaultValue) { - final Integer value = (Integer)mAttributes.get(index); - return super.getFlag(a, index, defaultValue) | (value != null ? value : 0); + if (a.hasValue(index)) { + return a.getInt(index, defaultValue); + } + final Integer styleValue = (Integer)mStyleAttributes.get(index); + return styleValue != null ? styleValue : defaultValue; } @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(); + public int getFlag(TypedArray a, int index) { + final int value = a.getInt(index, 0); + final Integer styleValue = (Integer)mStyleAttributes.get(index); + return (styleValue != null ? styleValue : 0) | value; } - private void parseKeyStyleAttributes(TypedArray keyAttr) { + void readKeyAttributes(TypedArray keyAttr) { // TODO: Currently not all Key attributes can be declared as style. readInt(keyAttr, R.styleable.Keyboard_Key_code); - 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); + readInt(keyAttr, R.styleable.Keyboard_Key_altCode); + readString(keyAttr, R.styleable.Keyboard_Key_keyLabel); + readString(keyAttr, R.styleable.Keyboard_Key_keyOutputText); + readString(keyAttr, R.styleable.Keyboard_Key_keyHintLabel); + readStringArray(keyAttr, R.styleable.Keyboard_Key_moreKeys); + readStringArray(keyAttr, R.styleable.Keyboard_Key_additionalMoreKeys); + readFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags); readInt(keyAttr, R.styleable.Keyboard_Key_keyIcon); + readInt(keyAttr, R.styleable.Keyboard_Key_keyIconDisabled); 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) { - if (a.hasValue(index)) - mAttributes.put(index, a.getText(index)); + private void readString(TypedArray a, int index) { + if (a.hasValue(index)) { + mStyleAttributes.put(index, a.getString(index)); + } } private void readInt(TypedArray a, int index) { - if (a.hasValue(index)) - mAttributes.put(index, a.getInt(index, 0)); + if (a.hasValue(index)) { + mStyleAttributes.put(index, a.getInt(index, 0)); + } } private void readFlag(TypedArray a, int index) { - final Integer value = (Integer)mAttributes.get(index); - if (a.hasValue(index)) - mAttributes.put(index, a.getInt(index, 0) | (value != null ? value : 0)); + final Integer value = (Integer)mStyleAttributes.get(index); + if (a.hasValue(index)) { + mStyleAttributes.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 readStringArray(TypedArray a, int index) { + final String[] value = parseStringArray(a, index); + if (value != null) { + mStyleAttributes.put(index, value); + } } - private void readTextArray(TypedArray a, int index) { - final CharSequence[] value = parseTextArray(a, index); - if (value != null) - mAttributes.put(index, value); + void addParentStyleAttributes(DeclaredKeyStyle parentStyle) { + mStyleAttributes.putAll(parentStyle.mStyleAttributes); } + } - private void addParent(DeclaredKeyStyle parentStyle) { - mAttributes.putAll(parentStyle.mAttributes); + static String[] parseStringArray(TypedArray a, int index) { + if (a.hasValue(index)) { + return KeySpecParser.parseCsvString( + a.getString(index), a.getResources(), R.string.english_ime_name); } + return null; } public void parseKeyStyleAttributes(TypedArray keyStyleAttr, TypedArray keyAttrs, - XmlPullParser parser) { + XmlPullParser parser) throws XmlPullParserException { final String styleName = keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName); - if (DEBUG) Log.d(TAG, String.format("<%s styleName=%s />", - KeyboardBuilder.TAG_KEY_STYLE, styleName)); - if (mStyles.containsKey(styleName)) - throw new ParseException("duplicate key style declared: " + styleName, parser); + if (DEBUG) { + Log.d(TAG, String.format("<%s styleName=%s />", + Keyboard.Builder.TAG_KEY_STYLE, styleName)); + } + if (mStyles.containsKey(styleName)) { + throw new XmlParseUtils.ParseException( + "duplicate key style declared: " + styleName, parser); + } final DeclaredKeyStyle style = new DeclaredKeyStyle(); if (keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_parentStyle)) { final String parentStyle = keyStyleAttr.getString( R.styleable.Keyboard_KeyStyle_parentStyle); final DeclaredKeyStyle parent = mStyles.get(parentStyle); - if (parent == null) - throw new ParseException("Unknown parentStyle " + parentStyle, parser); - style.addParent(parent); + if (parent == null) { + throw new XmlParseUtils.ParseException( + "Unknown parentStyle " + parentStyle, parser); + } + style.addParentStyleAttributes(parent); } - style.parseKeyStyleAttributes(keyAttrs); + style.readKeyAttributes(keyAttrs); mStyles.put(styleName, style); } @@ -235,7 +188,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/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java deleted file mode 100644 index de64639b0..000000000 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java +++ /dev/null @@ -1,893 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.keyboard.internal; - -import android.content.Context; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.util.DisplayMetrics; -import android.util.Log; -import android.util.TypedValue; -import android.util.Xml; -import android.view.InflateException; - -import com.android.inputmethod.compat.EditorInfoCompatUtils; -import com.android.inputmethod.keyboard.Key; -import com.android.inputmethod.keyboard.Keyboard; -import com.android.inputmethod.keyboard.KeyboardId; -import com.android.inputmethod.latin.LatinImeLogger; -import com.android.inputmethod.latin.R; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.Arrays; - -/** - * Keyboard Building helper. - * - * This class parses Keyboard XML file and eventually build a Keyboard. - * The Keyboard XML file looks like: - * <pre> - * >!-- xml/keyboard.xml --< - * >Keyboard keyboard_attributes*< - * >!-- Keyboard Content --< - * >Row row_attributes*< - * >!-- Row Content --< - * >Key key_attributes* /< - * >Spacer horizontalGap="0.2in" /< - * >include keyboardLayout="@xml/other_keys"< - * ... - * >/Row< - * >include keyboardLayout="@xml/other_rows"< - * ... - * >/Keyboard< - * </pre> - * The XML file which is included in other file must have >merge< as root element, such as: - * <pre> - * >!-- xml/other_keys.xml --< - * >merge< - * >Key key_attributes* /< - * ... - * >/merge< - * </pre> - * and - * <pre> - * >!-- xml/other_rows.xml --< - * >merge< - * >Row row_attributes*< - * >Key key_attributes* /< - * >/Row< - * ... - * >/merge< - * </pre> - * You can also use switch-case-default tags to select Rows and Keys. - * <pre> - * >switch< - * >case case_attribute*< - * >!-- Any valid tags at switch position --< - * >/case< - * ... - * >default< - * >!-- Any valid tags at switch position --< - * >/default< - * >/switch< - * </pre> - * You can declare Key style and specify styles within Key tags. - * <pre> - * >switch< - * >case mode="email"< - * >key-style styleName="f1-key" parentStyle="modifier-key" - * keyLabel=".com" - * /< - * >/case< - * >case mode="url"< - * >key-style styleName="f1-key" parentStyle="modifier-key" - * keyLabel="http://" - * /< - * >/case< - * >/switch< - * ... - * >Key keyStyle="shift-key" ... /< - * </pre> - */ - -public class KeyboardBuilder<KP extends KeyboardParams> { - private static final String TAG = KeyboardBuilder.class.getSimpleName(); - private static final boolean DEBUG = false; - - // Keyboard XML Tags - private static final String TAG_KEYBOARD = "Keyboard"; - private static final String TAG_ROW = "Row"; - private static final String TAG_KEY = "Key"; - private static final String TAG_SPACER = "Spacer"; - private static final String TAG_INCLUDE = "include"; - private static final String TAG_MERGE = "merge"; - private static final String TAG_SWITCH = "switch"; - private static final String TAG_CASE = "case"; - private static final String TAG_DEFAULT = "default"; - public static final String TAG_KEY_STYLE = "key-style"; - - private static final int DEFAULT_KEYBOARD_COLUMNS = 10; - private static final int DEFAULT_KEYBOARD_ROWS = 4; - - protected final KP mParams; - protected final Context mContext; - protected final Resources mResources; - private final DisplayMetrics mDisplayMetrics; - - private int mCurrentY = 0; - private Row mCurrentRow = null; - private boolean mLeftEdge; - private boolean mTopEdge; - private Key mRightEdgeKey = null; - private final KeyStyles mKeyStyles = new KeyStyles(); - - /** - * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate. - * Some of the key size defaults can be overridden per row from what the {@link Keyboard} - * defines. - */ - public static class Row { - // keyWidth enum constants - private static final int KEYWIDTH_NOT_ENUM = 0; - private static final int KEYWIDTH_FILL_RIGHT = -1; - private static final int KEYWIDTH_FILL_BOTH = -2; - - private final KeyboardParams mParams; - /** Default width of a key in this row. */ - public final float mDefaultKeyWidth; - /** Default height of a key in this row. */ - public final int mRowHeight; - - private final int mCurrentY; - // Will be updated by {@link Key}'s constructor. - private float mCurrentX; - - public Row(Resources res, KeyboardParams params, XmlPullParser parser, int y) { - mParams = params; - TypedArray keyboardAttr = res.obtainAttributes(Xml.asAttributeSet(parser), - R.styleable.Keyboard); - mRowHeight = (int)KeyboardBuilder.getDimensionOrFraction(keyboardAttr, - R.styleable.Keyboard_rowHeight, params.mBaseHeight, params.mDefaultRowHeight); - keyboardAttr.recycle(); - TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser), - R.styleable.Keyboard_Key); - mDefaultKeyWidth = KeyboardBuilder.getDimensionOrFraction(keyAttr, - R.styleable.Keyboard_Key_keyWidth, params.mBaseWidth, params.mDefaultKeyWidth); - keyAttr.recycle(); - - mCurrentY = y; - mCurrentX = 0.0f; - } - - public void setXPos(float keyXPos) { - mCurrentX = keyXPos; - } - - public void advanceXPos(float width) { - mCurrentX += width; - } - - public int getKeyY() { - return mCurrentY; - } - - public float getKeyX(TypedArray keyAttr) { - final int widthType = KeyboardBuilder.getEnumValue(keyAttr, - R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM); - if (widthType == KEYWIDTH_FILL_BOTH) { - // If keyWidth is fillBoth, the key width should start right after the nearest key - // on the left hand side. - return mCurrentX; - } - - final int keyboardRightEdge = mParams.mOccupiedWidth - mParams.mHorizontalEdgesPadding; - if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) { - final float keyXPos = KeyboardBuilder.getDimensionOrFraction(keyAttr, - R.styleable.Keyboard_Key_keyXPos, mParams.mBaseWidth, 0); - if (keyXPos < 0) { - // If keyXPos is negative, the actual x-coordinate will be - // keyboardWidth + keyXPos. - // keyXPos shouldn't be less than mCurrentX because drawable area for this key - // starts at mCurrentX. Or, this key will overlaps the adjacent key on its left - // hand side. - return Math.max(keyXPos + keyboardRightEdge, mCurrentX); - } else { - return keyXPos + mParams.mHorizontalEdgesPadding; - } - } - return mCurrentX; - } - - public float getKeyWidth(TypedArray keyAttr, float keyXPos) { - final int widthType = KeyboardBuilder.getEnumValue(keyAttr, - R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM); - switch (widthType) { - case KEYWIDTH_FILL_RIGHT: - case KEYWIDTH_FILL_BOTH: - final int keyboardRightEdge = - mParams.mOccupiedWidth - mParams.mHorizontalEdgesPadding; - // If keyWidth is fillRight, the actual key width will be determined to fill out the - // area up to the right edge of the keyboard. - // If keyWidth is fillBoth, the actual key width will be determined to fill out the - // area between the nearest key on the left hand side and the right edge of the - // keyboard. - return keyboardRightEdge - keyXPos; - default: // KEYWIDTH_NOT_ENUM - return KeyboardBuilder.getDimensionOrFraction(keyAttr, - R.styleable.Keyboard_Key_keyWidth, mParams.mBaseWidth, mDefaultKeyWidth); - } - } - } - - public KeyboardBuilder(Context context, KP params) { - mContext = context; - final Resources res = context.getResources(); - mResources = res; - mDisplayMetrics = res.getDisplayMetrics(); - - mParams = params; - - setTouchPositionCorrectionData(context, params); - - params.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width); - params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height); - } - - private static void setTouchPositionCorrectionData(Context context, KeyboardParams params) { - final TypedArray a = context.obtainStyledAttributes( - null, R.styleable.Keyboard, R.attr.keyboardStyle, 0); - params.mThemeId = a.getInt(R.styleable.Keyboard_themeId, 0); - final int resourceId = a.getResourceId(R.styleable.Keyboard_touchPositionCorrectionData, 0); - a.recycle(); - if (resourceId == 0) { - if (LatinImeLogger.sDBG) - throw new RuntimeException("touchPositionCorrectionData is not defined"); - return; - } - - final String[] data = context.getResources().getStringArray(resourceId); - params.mTouchPositionCorrection.load(data); - } - - public KeyboardBuilder<KP> load(KeyboardId id) { - mParams.mId = id; - final XmlResourceParser parser = mResources.getXml(id.getXmlId()); - try { - parseKeyboard(parser); - } catch (XmlPullParserException e) { - Log.w(TAG, "keyboard XML parse error: " + e); - throw new IllegalArgumentException(e); - } catch (IOException e) { - Log.w(TAG, "keyboard XML parse error: " + e); - throw new RuntimeException(e); - } finally { - parser.close(); - } - return this; - } - - public void setTouchPositionCorrectionEnabled(boolean enabled) { - mParams.mTouchPositionCorrection.setEnabled(enabled); - } - - public Keyboard build() { - return new Keyboard(mParams); - } - - private void parseKeyboard(XmlResourceParser parser) - throws XmlPullParserException, IOException { - if (DEBUG) Log.d(TAG, String.format("<%s> %s", TAG_KEYBOARD, mParams.mId)); - int event; - while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { - if (event == XmlPullParser.START_TAG) { - final String tag = parser.getName(); - if (TAG_KEYBOARD.equals(tag)) { - parseKeyboardAttributes(parser); - startKeyboard(); - parseKeyboardContent(parser, false); - break; - } else { - throw new IllegalStartTag(parser, TAG_KEYBOARD); - } - } - } - } - - public static String parseKeyboardLocale( - Context context, int resId) throws XmlPullParserException, IOException { - final Resources res = context.getResources(); - final XmlPullParser parser = res.getXml(resId); - if (parser == null) return ""; - int event; - while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { - if (event == XmlPullParser.START_TAG) { - final String tag = parser.getName(); - if (TAG_KEYBOARD.equals(tag)) { - final TypedArray keyboardAttr = res.obtainAttributes(Xml.asAttributeSet(parser), - R.styleable.Keyboard); - final String locale = keyboardAttr.getString( - R.styleable.Keyboard_keyboardLocale); - keyboardAttr.recycle(); - return locale; - } else { - throw new IllegalStartTag(parser, TAG_KEYBOARD); - } - } - } - return ""; - } - - private void parseKeyboardAttributes(XmlPullParser parser) { - final int displayWidth = mDisplayMetrics.widthPixels; - final TypedArray keyboardAttr = mContext.obtainStyledAttributes( - Xml.asAttributeSet(parser), R.styleable.Keyboard, R.attr.keyboardStyle, - R.style.Keyboard); - final TypedArray keyAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser), - R.styleable.Keyboard_Key); - try { - final int displayHeight = mDisplayMetrics.heightPixels; - final int keyboardHeight = (int)keyboardAttr.getDimension( - R.styleable.Keyboard_keyboardHeight, displayHeight / 2); - final int maxKeyboardHeight = (int)getDimensionOrFraction(keyboardAttr, - R.styleable.Keyboard_maxKeyboardHeight, displayHeight, displayHeight / 2); - int minKeyboardHeight = (int)getDimensionOrFraction(keyboardAttr, - R.styleable.Keyboard_minKeyboardHeight, displayHeight, displayHeight / 2); - if (minKeyboardHeight < 0) { - // Specified fraction was negative, so it should be calculated against display - // width. - minKeyboardHeight = -(int)getDimensionOrFraction(keyboardAttr, - R.styleable.Keyboard_minKeyboardHeight, displayWidth, displayWidth / 2); - } - final KeyboardParams params = mParams; - // Keyboard height will not exceed maxKeyboardHeight and will not be less than - // minKeyboardHeight. - params.mOccupiedHeight = Math.max( - Math.min(keyboardHeight, maxKeyboardHeight), minKeyboardHeight); - params.mOccupiedWidth = params.mId.mWidth; - params.mTopPadding = (int)getDimensionOrFraction(keyboardAttr, - R.styleable.Keyboard_keyboardTopPadding, params.mOccupiedHeight, 0); - params.mBottomPadding = (int)getDimensionOrFraction(keyboardAttr, - R.styleable.Keyboard_keyboardBottomPadding, params.mOccupiedHeight, 0); - params.mHorizontalEdgesPadding = (int)getDimensionOrFraction(keyboardAttr, - R.styleable.Keyboard_keyboardHorizontalEdgesPadding, mParams.mOccupiedWidth, 0); - - params.mBaseWidth = params.mOccupiedWidth - params.mHorizontalEdgesPadding * 2 - - params.mHorizontalCenterPadding; - params.mDefaultKeyWidth = (int)getDimensionOrFraction(keyAttr, - R.styleable.Keyboard_Key_keyWidth, params.mBaseWidth, - params.mBaseWidth / DEFAULT_KEYBOARD_COLUMNS); - params.mHorizontalGap = (int)getDimensionOrFraction(keyboardAttr, - R.styleable.Keyboard_horizontalGap, params.mBaseWidth, 0); - params.mVerticalGap = (int)getDimensionOrFraction(keyboardAttr, - R.styleable.Keyboard_verticalGap, params.mOccupiedHeight, 0); - params.mBaseHeight = params.mOccupiedHeight - params.mTopPadding - - params.mBottomPadding + params.mVerticalGap; - params.mDefaultRowHeight = (int)getDimensionOrFraction(keyboardAttr, - R.styleable.Keyboard_rowHeight, params.mBaseHeight, - params.mBaseHeight / DEFAULT_KEYBOARD_ROWS); - - params.mIsRtlKeyboard = keyboardAttr.getBoolean( - R.styleable.Keyboard_isRtlKeyboard, false); - params.mMoreKeysTemplate = keyboardAttr.getResourceId( - R.styleable.Keyboard_moreKeysTemplate, 0); - params.mMaxMiniKeyboardColumn = keyAttr.getInt( - R.styleable.Keyboard_Key_maxMoreKeysColumn, 5); - - params.mIconsSet.loadIcons(keyboardAttr); - } finally { - keyAttr.recycle(); - keyboardAttr.recycle(); - } - } - - private void parseKeyboardContent(XmlPullParser parser, boolean skip) - throws XmlPullParserException, IOException { - int event; - while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { - if (event == XmlPullParser.START_TAG) { - final String tag = parser.getName(); - if (TAG_ROW.equals(tag)) { - Row row = parseRowAttributes(parser); - if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_ROW)); - if (!skip) - startRow(row); - parseRowContent(parser, row, skip); - } else if (TAG_INCLUDE.equals(tag)) { - parseIncludeKeyboardContent(parser, skip); - } else if (TAG_SWITCH.equals(tag)) { - parseSwitchKeyboardContent(parser, skip); - } else if (TAG_KEY_STYLE.equals(tag)) { - parseKeyStyle(parser, skip); - } else { - throw new IllegalStartTag(parser, TAG_ROW); - } - } else if (event == XmlPullParser.END_TAG) { - final String tag = parser.getName(); - if (TAG_KEYBOARD.equals(tag)) { - endKeyboard(); - break; - } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag) - || TAG_MERGE.equals(tag)) { - if (DEBUG) Log.d(TAG, String.format("</%s>", tag)); - break; - } else if (TAG_KEY_STYLE.equals(tag)) { - continue; - } else { - throw new IllegalEndTag(parser, TAG_ROW); - } - } - } - } - - private Row parseRowAttributes(XmlPullParser parser) { - final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), - R.styleable.Keyboard); - try { - if (a.hasValue(R.styleable.Keyboard_horizontalGap)) - throw new IllegalAttribute(parser, "horizontalGap"); - if (a.hasValue(R.styleable.Keyboard_verticalGap)) - throw new IllegalAttribute(parser, "verticalGap"); - return new Row(mResources, mParams, parser, mCurrentY); - } finally { - a.recycle(); - } - } - - private void parseRowContent(XmlPullParser parser, Row row, boolean skip) - throws XmlPullParserException, IOException { - int event; - while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { - if (event == XmlPullParser.START_TAG) { - final String tag = parser.getName(); - if (TAG_KEY.equals(tag)) { - parseKey(parser, row, skip); - } else if (TAG_SPACER.equals(tag)) { - parseSpacer(parser, row, skip); - } else if (TAG_INCLUDE.equals(tag)) { - parseIncludeRowContent(parser, row, skip); - } else if (TAG_SWITCH.equals(tag)) { - parseSwitchRowContent(parser, row, skip); - } else if (TAG_KEY_STYLE.equals(tag)) { - parseKeyStyle(parser, skip); - } else { - throw new IllegalStartTag(parser, TAG_KEY); - } - } else if (event == XmlPullParser.END_TAG) { - final String tag = parser.getName(); - if (TAG_ROW.equals(tag)) { - if (DEBUG) Log.d(TAG, String.format("</%s>", TAG_ROW)); - if (!skip) - endRow(row); - break; - } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag) - || TAG_MERGE.equals(tag)) { - if (DEBUG) Log.d(TAG, String.format("</%s>", tag)); - break; - } else if (TAG_KEY_STYLE.equals(tag)) { - continue; - } else { - throw new IllegalEndTag(parser, TAG_KEY); - } - } - } - } - - private void parseKey(XmlPullParser parser, Row row, boolean skip) - throws XmlPullParserException, IOException { - if (skip) { - checkEndTag(TAG_KEY, parser); - } else { - final Key key = new Key(mResources, mParams, row, parser, mKeyStyles); - if (DEBUG) Log.d(TAG, String.format("<%s%s keyLabel=%s code=%d moreKeys=%s />", - TAG_KEY, (key.isEnabled() ? "" : " disabled"), key.mLabel, key.mCode, - Arrays.toString(key.mMoreKeys))); - checkEndTag(TAG_KEY, parser); - endKey(key); - } - } - - private void parseSpacer(XmlPullParser parser, Row row, boolean skip) - throws XmlPullParserException, IOException { - if (skip) { - checkEndTag(TAG_SPACER, parser); - } else { - final Key.Spacer spacer = new Key.Spacer(mResources, mParams, row, parser, mKeyStyles); - if (DEBUG) Log.d(TAG, String.format("<%s />", TAG_SPACER)); - checkEndTag(TAG_SPACER, parser); - endKey(spacer); - } - } - - private void parseIncludeKeyboardContent(XmlPullParser parser, boolean skip) - throws XmlPullParserException, IOException { - parseIncludeInternal(parser, null, skip); - } - - private void parseIncludeRowContent(XmlPullParser parser, Row row, boolean skip) - throws XmlPullParserException, IOException { - parseIncludeInternal(parser, row, skip); - } - - private void parseIncludeInternal(XmlPullParser parser, Row row, boolean skip) - throws XmlPullParserException, IOException { - if (skip) { - checkEndTag(TAG_INCLUDE, parser); - } else { - final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), - R.styleable.Keyboard_Include); - final int keyboardLayout = a.getResourceId( - R.styleable.Keyboard_Include_keyboardLayout, 0); - a.recycle(); - - checkEndTag(TAG_INCLUDE, parser); - if (keyboardLayout == 0) - throw new ParseException("No keyboardLayout attribute in <include/>", parser); - if (DEBUG) Log.d(TAG, String.format("<%s keyboardLayout=%s />", - TAG_INCLUDE, mResources.getResourceEntryName(keyboardLayout))); - final XmlResourceParser parserForInclude = mResources.getXml(keyboardLayout); - try { - parseMerge(parserForInclude, row, skip); - } finally { - parserForInclude.close(); - } - } - } - - private void parseMerge(XmlPullParser parser, Row row, boolean skip) - throws XmlPullParserException, IOException { - int event; - while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { - if (event == XmlPullParser.START_TAG) { - final String tag = parser.getName(); - if (TAG_MERGE.equals(tag)) { - if (row == null) { - parseKeyboardContent(parser, skip); - } else { - parseRowContent(parser, row, skip); - } - break; - } else { - throw new ParseException( - "Included keyboard layout must have <merge> root element", parser); - } - } - } - } - - private void parseSwitchKeyboardContent(XmlPullParser parser, boolean skip) - throws XmlPullParserException, IOException { - parseSwitchInternal(parser, null, skip); - } - - private void parseSwitchRowContent(XmlPullParser parser, Row row, boolean skip) - throws XmlPullParserException, IOException { - parseSwitchInternal(parser, row, skip); - } - - private void parseSwitchInternal(XmlPullParser parser, Row row, boolean skip) - throws XmlPullParserException, IOException { - if (DEBUG) Log.d(TAG, String.format("<%s> %s", TAG_SWITCH, mParams.mId)); - boolean selected = false; - int event; - while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { - if (event == XmlPullParser.START_TAG) { - final String tag = parser.getName(); - if (TAG_CASE.equals(tag)) { - selected |= parseCase(parser, row, selected ? true : skip); - } else if (TAG_DEFAULT.equals(tag)) { - selected |= parseDefault(parser, row, selected ? true : skip); - } else { - throw new IllegalStartTag(parser, TAG_KEY); - } - } else if (event == XmlPullParser.END_TAG) { - final String tag = parser.getName(); - if (TAG_SWITCH.equals(tag)) { - if (DEBUG) Log.d(TAG, String.format("</%s>", TAG_SWITCH)); - break; - } else { - throw new IllegalEndTag(parser, TAG_KEY); - } - } - } - } - - private boolean parseCase(XmlPullParser parser, Row row, boolean skip) - throws XmlPullParserException, IOException { - final boolean selected = parseCaseCondition(parser); - if (row == null) { - // Processing Rows. - parseKeyboardContent(parser, selected ? skip : true); - } else { - // Processing Keys. - parseRowContent(parser, row, selected ? skip : true); - } - return selected; - } - - private boolean parseCaseCondition(XmlPullParser parser) { - final KeyboardId id = mParams.mId; - if (id == null) - return true; - - final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), - R.styleable.Keyboard_Case); - try { - final boolean modeMatched = matchTypedValue(a, - R.styleable.Keyboard_Case_mode, id.mMode, KeyboardId.modeName(id.mMode)); - final boolean navigateActionMatched = matchBoolean(a, - R.styleable.Keyboard_Case_navigateAction, id.mNavigateAction); - final boolean passwordInputMatched = matchBoolean(a, - R.styleable.Keyboard_Case_passwordInput, id.mPasswordInput); - final boolean hasSettingsKeyMatched = matchBoolean(a, - R.styleable.Keyboard_Case_hasSettingsKey, id.mHasSettingsKey); - final boolean f2KeyModeMatched = matchInteger(a, - R.styleable.Keyboard_Case_f2KeyMode, id.mF2KeyMode); - final boolean clobberSettingsKeyMatched = matchBoolean(a, - R.styleable.Keyboard_Case_clobberSettingsKey, id.mClobberSettingsKey); - final boolean shortcutKeyEnabledMatched = matchBoolean(a, - R.styleable.Keyboard_Case_shortcutKeyEnabled, id.mShortcutKeyEnabled); - final boolean hasShortcutKeyMatched = matchBoolean(a, - R.styleable.Keyboard_Case_hasShortcutKey, id.mHasShortcutKey); - // As noted at {@link KeyboardId} class, we are interested only in enum value masked by - // {@link android.view.inputmethod.EditorInfo#IME_MASK_ACTION} and - // {@link android.view.inputmethod.EditorInfo#IME_FLAG_NO_ENTER_ACTION}. So matching - // this attribute with id.mImeOptions as integer value is enough for our purpose. - final boolean imeActionMatched = matchInteger(a, - R.styleable.Keyboard_Case_imeAction, id.mImeAction); - final boolean localeCodeMatched = matchString(a, - R.styleable.Keyboard_Case_localeCode, id.mLocale.toString()); - final boolean languageCodeMatched = matchString(a, - R.styleable.Keyboard_Case_languageCode, id.mLocale.getLanguage()); - final boolean countryCodeMatched = matchString(a, - R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry()); - final boolean selected = modeMatched && navigateActionMatched && passwordInputMatched - && hasSettingsKeyMatched && f2KeyModeMatched && clobberSettingsKeyMatched - && shortcutKeyEnabledMatched && hasShortcutKeyMatched && imeActionMatched && - localeCodeMatched && languageCodeMatched && countryCodeMatched; - - if (DEBUG) Log.d(TAG, String.format("<%s%s%s%s%s%s%s%s%s%s%s%s%s> %s", TAG_CASE, - textAttr(a.getString(R.styleable.Keyboard_Case_mode), "mode"), - booleanAttr(a, R.styleable.Keyboard_Case_navigateAction, "navigateAction"), - booleanAttr(a, R.styleable.Keyboard_Case_passwordInput, "passwordInput"), - booleanAttr(a, R.styleable.Keyboard_Case_hasSettingsKey, "hasSettingsKey"), - textAttr(KeyboardId.f2KeyModeName( - a.getInt(R.styleable.Keyboard_Case_f2KeyMode, -1)), "f2KeyMode"), - booleanAttr(a, R.styleable.Keyboard_Case_clobberSettingsKey, - "clobberSettingsKey"), - booleanAttr( - a, R.styleable.Keyboard_Case_shortcutKeyEnabled, "shortcutKeyEnabled"), - booleanAttr(a, R.styleable.Keyboard_Case_hasShortcutKey, "hasShortcutKey"), - textAttr(EditorInfoCompatUtils.imeOptionsName( - a.getInt(R.styleable.Keyboard_Case_imeAction, -1)), "imeAction"), - textAttr(a.getString(R.styleable.Keyboard_Case_localeCode), "localeCode"), - textAttr(a.getString(R.styleable.Keyboard_Case_languageCode), "languageCode"), - textAttr(a.getString(R.styleable.Keyboard_Case_countryCode), "countryCode"), - Boolean.toString(selected))); - - return selected; - } finally { - a.recycle(); - } - } - - private static boolean matchInteger(TypedArray a, int index, int value) { - // If <case> does not have "index" attribute, that means this <case> is wild-card for the - // attribute. - return !a.hasValue(index) || a.getInt(index, 0) == value; - } - - private static boolean matchBoolean(TypedArray a, int index, boolean value) { - // If <case> does not have "index" attribute, that means this <case> is wild-card for the - // attribute. - return !a.hasValue(index) || a.getBoolean(index, false) == value; - } - - private static boolean matchString(TypedArray a, int index, String value) { - // If <case> does not have "index" attribute, that means this <case> is wild-card for the - // attribute. - return !a.hasValue(index) || stringArrayContains(a.getString(index).split("\\|"), value); - } - - private static boolean matchTypedValue(TypedArray a, int index, int intValue, String strValue) { - // If <case> does not have "index" attribute, that means this <case> is wild-card for the - // attribute. - final TypedValue v = a.peekValue(index); - if (v == null) - return true; - - if (isIntegerValue(v)) { - return intValue == a.getInt(index, 0); - } else if (isStringValue(v)) { - return stringArrayContains(a.getString(index).split("\\|"), strValue); - } - return false; - } - - private static boolean stringArrayContains(String[] array, String value) { - for (final String elem : array) { - if (elem.equals(value)) - return true; - } - return false; - } - - private boolean parseDefault(XmlPullParser parser, Row row, boolean skip) - throws XmlPullParserException, IOException { - if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_DEFAULT)); - if (row == null) { - parseKeyboardContent(parser, skip); - } else { - parseRowContent(parser, row, skip); - } - return true; - } - - private void parseKeyStyle(XmlPullParser parser, boolean skip) { - TypedArray keyStyleAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser), - R.styleable.Keyboard_KeyStyle); - TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser), - R.styleable.Keyboard_Key); - try { - if (!keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_styleName)) - throw new ParseException("<" + TAG_KEY_STYLE - + "/> needs styleName attribute", parser); - if (!skip) - mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser); - } finally { - keyStyleAttr.recycle(); - keyAttrs.recycle(); - } - } - - private static void checkEndTag(String tag, XmlPullParser parser) - throws XmlPullParserException, IOException { - if (parser.next() == XmlPullParser.END_TAG && tag.equals(parser.getName())) - return; - throw new NonEmptyTag(tag, parser); - } - - private void startKeyboard() { - mCurrentY += mParams.mTopPadding; - mTopEdge = true; - } - - private void startRow(Row row) { - addEdgeSpace(mParams.mHorizontalEdgesPadding, row); - mCurrentRow = row; - mLeftEdge = true; - mRightEdgeKey = null; - } - - private void endRow(Row row) { - if (mCurrentRow == null) - throw new InflateException("orphant end row tag"); - if (mRightEdgeKey != null) { - mRightEdgeKey.markAsRightEdge(mParams); - mRightEdgeKey = null; - } - addEdgeSpace(mParams.mHorizontalEdgesPadding, row); - mCurrentY += row.mRowHeight; - mCurrentRow = null; - mTopEdge = false; - } - - private void endKey(Key key) { - mParams.onAddKey(key); - if (mLeftEdge) { - key.markAsLeftEdge(mParams); - mLeftEdge = false; - } - if (mTopEdge) { - key.markAsTopEdge(mParams); - } - mRightEdgeKey = key; - } - - private void endKeyboard() { - } - - private void addEdgeSpace(float width, Row row) { - row.advanceXPos(width); - mLeftEdge = false; - mRightEdgeKey = null; - } - - public static float getDimensionOrFraction(TypedArray a, int index, int base, float defValue) { - final TypedValue value = a.peekValue(index); - if (value == null) - return defValue; - if (isFractionValue(value)) { - return a.getFraction(index, base, base, defValue); - } else if (isDimensionValue(value)) { - return a.getDimension(index, defValue); - } - return defValue; - } - - public static int getEnumValue(TypedArray a, int index, int defValue) { - final TypedValue value = a.peekValue(index); - if (value == null) - return defValue; - if (isIntegerValue(value)) { - return a.getInt(index, defValue); - } - return defValue; - } - - private static boolean isFractionValue(TypedValue v) { - return v.type == TypedValue.TYPE_FRACTION; - } - - private static boolean isDimensionValue(TypedValue v) { - return v.type == TypedValue.TYPE_DIMENSION; - } - - private static boolean isIntegerValue(TypedValue v) { - return v.type >= TypedValue.TYPE_FIRST_INT && v.type <= TypedValue.TYPE_LAST_INT; - } - - private static boolean isStringValue(TypedValue v) { - return v.type == TypedValue.TYPE_STRING; - } - - @SuppressWarnings("serial") - public static class ParseException extends InflateException { - public ParseException(String msg, XmlPullParser parser) { - super(msg + " at line " + parser.getLineNumber()); - } - } - - @SuppressWarnings("serial") - private static class IllegalStartTag extends ParseException { - public IllegalStartTag(XmlPullParser parser, String parent) { - super("Illegal start tag " + parser.getName() + " in " + parent, parser); - } - } - - @SuppressWarnings("serial") - private static class IllegalEndTag extends ParseException { - public IllegalEndTag(XmlPullParser parser, String parent) { - super("Illegal end tag " + parser.getName() + " in " + parent, parser); - } - } - - @SuppressWarnings("serial") - private static class IllegalAttribute extends ParseException { - public IllegalAttribute(XmlPullParser parser, String attribute) { - super("Tag " + parser.getName() + " has illegal attribute " + attribute, parser); - } - } - - @SuppressWarnings("serial") - private static class NonEmptyTag extends ParseException { - public NonEmptyTag(String tag, XmlPullParser parser) { - super(tag + " must be empty tag", parser); - } - } - - private static String textAttr(String value, String name) { - return value != null ? String.format(" %s=%s", name, value) : ""; - } - - private static String booleanAttr(TypedArray a, int index, String name) { - return a.hasValue(index) ? String.format(" %s=%s", name, a.getBoolean(index, false)) : ""; - } -} diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java index faa5f86f2..162e96d06 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java @@ -23,86 +23,92 @@ import android.util.Log; import com.android.inputmethod.latin.R; +import java.util.HashMap; +import java.util.Map; + public class KeyboardIconsSet { private static final String TAG = KeyboardIconsSet.class.getSimpleName(); public static final int ICON_UNDEFINED = 0; + // The value should be aligned with the enum value of Key.keyIcon. + public static final int ICON_SPACE = 4; + private static final int NUM_ICONS = 13; + + private final Drawable[] mIcons = new Drawable[NUM_ICONS + 1]; - // This should be aligned with Keyboard.keyIcon enum. - private static final int ICON_SHIFT_KEY = 1; - private static final int ICON_DELETE_KEY = 2; - private static final int ICON_SETTINGS_KEY = 3; // This is also represented as "@icon/3" in XML. - private static final int ICON_SPACE_KEY = 4; - private static final int ICON_RETURN_KEY = 5; - private static final int ICON_SEARCH_KEY = 6; - private static final int ICON_TAB_KEY = 7; // This is also represented as "@icon/7" in XML. - private static final int ICON_SHORTCUT_KEY = 8; - private static final int ICON_SHORTCUT_FOR_LABEL = 9; - // This should be aligned with Keyboard.keyIconShifted enum. - private static final int ICON_SHIFTED_SHIFT_KEY = 10; - // This should be aligned with Keyboard.keyIconPreview enum. - private static final int ICON_PREVIEW_TAB_KEY = 11; - - private static final int ICON_LAST = 11; - - private final Drawable mIcons[] = new Drawable[ICON_LAST + 1]; - - private static final int getIconId(final int attrIndex) { - switch (attrIndex) { - case R.styleable.Keyboard_iconShiftKey: - return ICON_SHIFT_KEY; - case R.styleable.Keyboard_iconDeleteKey: - return ICON_DELETE_KEY; - case R.styleable.Keyboard_iconSettingsKey: - return ICON_SETTINGS_KEY; - case R.styleable.Keyboard_iconSpaceKey: - return ICON_SPACE_KEY; - case R.styleable.Keyboard_iconReturnKey: - return ICON_RETURN_KEY; - case R.styleable.Keyboard_iconSearchKey: - return ICON_SEARCH_KEY; - case R.styleable.Keyboard_iconTabKey: - return ICON_TAB_KEY; - case R.styleable.Keyboard_iconShortcutKey: - return ICON_SHORTCUT_KEY; - case R.styleable.Keyboard_iconShortcutForLabel: - return ICON_SHORTCUT_FOR_LABEL; - case R.styleable.Keyboard_iconShiftedShiftKey: - return ICON_SHIFTED_SHIFT_KEY; - case R.styleable.Keyboard_iconPreviewTabKey: - return ICON_PREVIEW_TAB_KEY; - default: - return ICON_UNDEFINED; + private static final Map<Integer, Integer> ATTR_ID_TO_ICON_ID = new HashMap<Integer, Integer>(); + private static final Map<String, Integer> NAME_TO_ICON_ID = new HashMap<String, Integer>(); + private static final String[] ICON_NAMES = new String[NUM_ICONS + 1]; + + private static final int ATTR_UNDEFINED = 0; + static { + // The key value should be aligned with the enum value of Key.keyIcon. + addIconIdMap(0, "undefined", ATTR_UNDEFINED); + addIconIdMap(1, "shiftKey", R.styleable.Keyboard_iconShiftKey); + addIconIdMap(2, "deleteKey", R.styleable.Keyboard_iconDeleteKey); + addIconIdMap(3, "settingsKey", R.styleable.Keyboard_iconSettingsKey); + addIconIdMap(4, "spaceKey", R.styleable.Keyboard_iconSpaceKey); + addIconIdMap(5, "returnKey", R.styleable.Keyboard_iconReturnKey); + addIconIdMap(6, "searchKey", R.styleable.Keyboard_iconSearchKey); + addIconIdMap(7, "tabKey", R.styleable.Keyboard_iconTabKey); + addIconIdMap(8, "shortcutKey", R.styleable.Keyboard_iconShortcutKey); + addIconIdMap(9, "shortcutForLabel", R.styleable.Keyboard_iconShortcutForLabel); + addIconIdMap(10, "spaceKeyForNumberLayout", + R.styleable.Keyboard_iconSpaceKeyForNumberLayout); + addIconIdMap(11, "shiftKeyShifted", R.styleable.Keyboard_iconShiftKeyShifted); + addIconIdMap(12, "disabledShortcurKey", R.styleable.Keyboard_iconDisabledShortcutKey); + addIconIdMap(13, "previewTabKey", R.styleable.Keyboard_iconPreviewTabKey); + } + + private static void addIconIdMap(int iconId, String name, int attrId) { + if (attrId != ATTR_UNDEFINED) { + ATTR_ID_TO_ICON_ID.put(attrId, iconId); } + NAME_TO_ICON_ID.put(name, iconId); + ICON_NAMES[iconId] = name; } public void loadIcons(final TypedArray keyboardAttrs) { - final int count = keyboardAttrs.getIndexCount(); - for (int i = 0; i < count; i++) { - final int attrIndex = keyboardAttrs.getIndex(i); - final int iconId = getIconId(attrIndex); - if (iconId != ICON_UNDEFINED) { - try { - mIcons[iconId] = setDefaultBounds(keyboardAttrs.getDrawable(attrIndex)); - } catch (Resources.NotFoundException e) { - Log.w(TAG, "Drawable resource for icon #" + iconId + " not found"); - } + for (final Integer attrId : ATTR_ID_TO_ICON_ID.keySet()) { + try { + final Drawable icon = keyboardAttrs.getDrawable(attrId); + setDefaultBounds(icon); + final Integer iconId = ATTR_ID_TO_ICON_ID.get(attrId); + mIcons[iconId] = icon; + } catch (Resources.NotFoundException e) { + Log.w(TAG, "Drawable resource for icon #" + + keyboardAttrs.getResources().getResourceEntryName(attrId) + + " not found"); } } } - public Drawable getIcon(final int iconId) { - if (iconId == ICON_UNDEFINED) - return null; - if (iconId < 0 || iconId >= mIcons.length) - throw new IllegalArgumentException("icon id is out of range: " + iconId); - return mIcons[iconId]; + private static boolean isValidIconId(final int iconId) { + return iconId >= 0 && iconId < ICON_NAMES.length; + } + + public static String getIconName(final int iconId) { + return isValidIconId(iconId) ? ICON_NAMES[iconId] : "unknown<" + iconId + ">"; + } + + public static int getIconId(final String name) { + final Integer iconId = NAME_TO_ICON_ID.get(name); + if (iconId != null) { + return iconId; + } + throw new RuntimeException("unknown icon name: " + name); + } + + public Drawable getIconDrawable(final int iconId) { + if (isValidIconId(iconId)) { + return mIcons[iconId]; + } + throw new RuntimeException("unknown icon id: " + getIconName(iconId)); } - private static Drawable setDefaultBounds(final Drawable icon) { + private static void setDefaultBounds(final Drawable icon) { if (icon != null) { icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); } - return icon; } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java deleted file mode 100644 index 64cd37c4b..000000000 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.keyboard.internal; - -import android.graphics.drawable.Drawable; - -import com.android.inputmethod.keyboard.Key; -import com.android.inputmethod.keyboard.Keyboard; -import com.android.inputmethod.keyboard.KeyboardId; -import com.android.inputmethod.latin.LatinImeLogger; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class KeyboardParams { - public KeyboardId mId; - public int mThemeId; - - /** Total height and width of the keyboard, including the paddings and keys */ - public int mOccupiedHeight; - public int mOccupiedWidth; - - /** Base height and width of the keyboard used to calculate rows' or keys' heights and widths */ - public int mBaseHeight; - public int mBaseWidth; - - public int mTopPadding; - public int mBottomPadding; - public int mHorizontalEdgesPadding; - public int mHorizontalCenterPadding; - - public int mDefaultRowHeight; - public int mDefaultKeyWidth; - public int mHorizontalGap; - public int mVerticalGap; - - public boolean mIsRtlKeyboard; - public int mMoreKeysTemplate; - public int mMaxMiniKeyboardColumn; - - public int GRID_WIDTH; - public int GRID_HEIGHT; - - public final List<Key> mKeys = new ArrayList<Key>(); - public final List<Key> mShiftKeys = new ArrayList<Key>(); - public final Set<Key> mShiftLockKeys = new HashSet<Key>(); - public final Map<Key, Drawable> mShiftedIcons = new HashMap<Key, Drawable>(); - public final Map<Key, Drawable> mUnshiftedIcons = new HashMap<Key, Drawable>(); - public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); - - public int mMostCommonKeyHeight = 0; - public int mMostCommonKeyWidth = 0; - - public final TouchPositionCorrection mTouchPositionCorrection = new TouchPositionCorrection(); - - public static class TouchPositionCorrection { - private static final int TOUCH_POSITION_CORRECTION_RECORD_SIZE = 3; - - public boolean mEnabled; - public float[] mXs; - public float[] mYs; - public float[] mRadii; - - public void load(String[] data) { - final int dataLength = data.length; - if (dataLength % TOUCH_POSITION_CORRECTION_RECORD_SIZE != 0) { - if (LatinImeLogger.sDBG) - throw new RuntimeException( - "the size of touch position correction data is invalid"); - return; - } - - final int length = dataLength / TOUCH_POSITION_CORRECTION_RECORD_SIZE; - mXs = new float[length]; - mYs = new float[length]; - mRadii = new float[length]; - try { - for (int i = 0; i < dataLength; ++i) { - final int type = i % TOUCH_POSITION_CORRECTION_RECORD_SIZE; - final int index = i / TOUCH_POSITION_CORRECTION_RECORD_SIZE; - final float value = Float.parseFloat(data[i]); - if (type == 0) { - mXs[index] = value; - } else if (type == 1) { - mYs[index] = value; - } else { - mRadii[index] = value; - } - } - } catch (NumberFormatException e) { - if (LatinImeLogger.sDBG) { - throw new RuntimeException( - "the number format for touch position correction data is invalid"); - } - mXs = null; - mYs = null; - mRadii = null; - } - } - - public void setEnabled(boolean enabled) { - mEnabled = enabled; - } - - public boolean isValid() { - return mEnabled && mXs != null && mYs != null && mRadii != null - && mXs.length > 0 && mYs.length > 0 && mRadii.length > 0; - } - } - - protected void clearKeys() { - mKeys.clear(); - mShiftKeys.clear(); - mShiftLockKeys.clear(); - mShiftedIcons.clear(); - mUnshiftedIcons.clear(); - clearHistogram(); - } - - public void onAddKey(Key key) { - mKeys.add(key); - updateHistogram(key); - if (key.mCode == Keyboard.CODE_SHIFT) { - mShiftKeys.add(key); - if (key.isSticky()) { - mShiftLockKeys.add(key); - } - } - } - - public void addShiftedIcon(Key key, Drawable icon) { - mUnshiftedIcons.put(key, key.getIcon()); - mShiftedIcons.put(key, icon); - } - - private int mMaxHeightCount = 0; - private int mMaxWidthCount = 0; - private final Map<Integer, Integer> mHeightHistogram = new HashMap<Integer, Integer>(); - private final Map<Integer, Integer> mWidthHistogram = new HashMap<Integer, Integer>(); - - private void clearHistogram() { - mMostCommonKeyHeight = 0; - mMaxHeightCount = 0; - mHeightHistogram.clear(); - - mMaxWidthCount = 0; - mMostCommonKeyWidth = 0; - mWidthHistogram.clear(); - } - - private static int updateHistogramCounter(Map<Integer, Integer> histogram, Integer key) { - final int count = (histogram.containsKey(key) ? histogram.get(key) : 0) + 1; - histogram.put(key, count); - return count; - } - - private void updateHistogram(Key key) { - final Integer height = key.mHeight + key.mVerticalGap; - final int heightCount = updateHistogramCounter(mHeightHistogram, height); - if (heightCount > mMaxHeightCount) { - mMaxHeightCount = heightCount; - mMostCommonKeyHeight = height; - } - - final Integer width = key.mWidth + key.mHorizontalGap; - final int widthCount = updateHistogramCounter(mWidthHistogram, width); - if (widthCount > mMaxWidthCount) { - mMaxWidthCount = widthCount; - mMostCommonKeyWidth = width; - } - } -} 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..cb8b4f05c --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java @@ -0,0 +1,588 @@ +/* + * 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; + +import android.text.TextUtils; +import android.util.Log; + +import com.android.inputmethod.keyboard.Keyboard; + +/** + * Keyboard state machine. + * + * This class contains all keyboard state transition logic. + * + * The input events are {@link #onLoadKeyboard(String)}, {@link #onSaveKeyboardState()}, + * {@link #onPressKey(int)}, {@link #onReleaseKey(int, boolean)}, + * {@link #onCodeInput(int, boolean, boolean)}, {@link #onCancelInput(boolean)}, + * {@link #onUpdateShiftState(boolean)}, {@link #onLongPressTimeout(int)}. + * + * The actions are {@link SwitchActions}'s methods. + */ +public class KeyboardState { + private static final String TAG = KeyboardState.class.getSimpleName(); + private static final boolean DEBUG_EVENT = false; + private static final boolean DEBUG_ACTION = false; + + public interface SwitchActions { + public void setAlphabetKeyboard(); + public void setAlphabetManualShiftedKeyboard(); + public void setAlphabetAutomaticShiftedKeyboard(); + public void setAlphabetShiftLockedKeyboard(); + public void setAlphabetShiftLockShiftedKeyboard(); + public void setSymbolsKeyboard(); + public void setSymbolsShiftedKeyboard(); + + /** + * Request to call back {@link KeyboardState#onUpdateShiftState(boolean)}. + */ + public void requestUpdatingShiftState(); + + public void startDoubleTapTimer(); + public boolean isInDoubleTapTimeout(); + public void startLongPressTimer(int code); + public void hapticAndAudioFeedback(int code); + } + + private final SwitchActions mSwitchActions; + + private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift"); + private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol"); + + // TODO: Merge {@link #mSwitchState}, {@link #mIsAlphabetMode}, {@link #mAlphabetShiftState}, + // {@link #mIsSymbolShifted}, {@link #mPrevMainKeyboardWasShiftLocked}, and + // {@link #mPrevSymbolsKeyboardWasShifted} into single state variable. + 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; + private static final int SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL = 3; + private static final int SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE = 4; + private int mSwitchState = SWITCH_STATE_ALPHA; + private String mLayoutSwitchBackSymbols; + + private boolean mIsAlphabetMode; + private AlphabetShiftState mAlphabetShiftState = new AlphabetShiftState(); + private boolean mIsSymbolShifted; + private boolean mPrevMainKeyboardWasShiftLocked; + private boolean mPrevSymbolsKeyboardWasShifted; + + // For handling double tap. + private boolean mIsInAlphabetUnshiftedFromShifted; + private boolean mIsInDoubleTapShiftKey; + + private final SavedKeyboardState mSavedKeyboardState = new SavedKeyboardState(); + + static class SavedKeyboardState { + public boolean mIsValid; + public boolean mIsAlphabetMode; + public boolean mIsAlphabetShiftLocked; + public boolean mIsShifted; + + @Override + public String toString() { + if (!mIsValid) return "INVALID"; + if (mIsAlphabetMode) { + if (mIsAlphabetShiftLocked) return "ALPHABET_SHIFT_LOCKED"; + return mIsShifted ? "ALPHABET_SHIFTED" : "ALPHABET"; + } else { + return mIsShifted ? "SYMBOLS_SHIFTED" : "SYMBOLS"; + } + } + } + + public KeyboardState(SwitchActions switchActions) { + mSwitchActions = switchActions; + } + + public void onLoadKeyboard(String layoutSwitchBackSymbols) { + if (DEBUG_EVENT) { + Log.d(TAG, "onLoadKeyboard: " + this); + } + mLayoutSwitchBackSymbols = layoutSwitchBackSymbols; + // Reset alphabet shift state. + mAlphabetShiftState.setShiftLocked(false); + mPrevMainKeyboardWasShiftLocked = false; + mPrevSymbolsKeyboardWasShifted = false; + mShiftKeyState.onRelease(); + mSymbolKeyState.onRelease(); + onRestoreKeyboardState(); + } + + public void onSaveKeyboardState() { + final SavedKeyboardState state = mSavedKeyboardState; + state.mIsAlphabetMode = mIsAlphabetMode; + if (mIsAlphabetMode) { + state.mIsAlphabetShiftLocked = mAlphabetShiftState.isShiftLocked(); + state.mIsShifted = !state.mIsAlphabetShiftLocked + && mAlphabetShiftState.isShiftedOrShiftLocked(); + } else { + state.mIsAlphabetShiftLocked = mPrevMainKeyboardWasShiftLocked; + state.mIsShifted = mIsSymbolShifted; + } + state.mIsValid = true; + if (DEBUG_EVENT) { + Log.d(TAG, "onSaveKeyboardState: saved=" + state + " " + this); + } + } + + private void onRestoreKeyboardState() { + final SavedKeyboardState state = mSavedKeyboardState; + if (DEBUG_EVENT) { + Log.d(TAG, "onRestoreKeyboardState: saved=" + state + " " + this); + } + if (!state.mIsValid || state.mIsAlphabetMode) { + setAlphabetKeyboard(); + } else { + if (state.mIsShifted) { + setSymbolsShiftedKeyboard(); + } else { + setSymbolsKeyboard(); + } + } + + if (!state.mIsValid) return; + state.mIsValid = false; + + if (state.mIsAlphabetMode) { + setShiftLocked(state.mIsAlphabetShiftLocked); + if (!state.mIsAlphabetShiftLocked) { + setShifted(state.mIsShifted ? MANUAL_SHIFT : UNSHIFT); + } + } else { + mPrevMainKeyboardWasShiftLocked = state.mIsAlphabetShiftLocked; + } + } + + private static final int UNSHIFT = 0; + private static final int MANUAL_SHIFT = 1; + private static final int AUTOMATIC_SHIFT = 2; + private static final int SHIFT_LOCK_SHIFTED = 3; + + private void setShifted(int shiftMode) { + if (DEBUG_ACTION) { + Log.d(TAG, "setShifted: shiftMode=" + shiftModeToString(shiftMode) + " " + this); + } + if (!mIsAlphabetMode) return; + final int prevShiftMode; + if (mAlphabetShiftState.isAutomaticShifted()) { + prevShiftMode = AUTOMATIC_SHIFT; + } else if (mAlphabetShiftState.isManualShifted()) { + prevShiftMode = MANUAL_SHIFT; + } else { + prevShiftMode = UNSHIFT; + } + switch (shiftMode) { + case AUTOMATIC_SHIFT: + mAlphabetShiftState.setAutomaticShifted(); + if (shiftMode != prevShiftMode) { + mSwitchActions.setAlphabetAutomaticShiftedKeyboard(); + } + break; + case MANUAL_SHIFT: + mAlphabetShiftState.setShifted(true); + if (shiftMode != prevShiftMode) { + mSwitchActions.setAlphabetManualShiftedKeyboard(); + } + break; + case UNSHIFT: + mAlphabetShiftState.setShifted(false); + if (shiftMode != prevShiftMode) { + mSwitchActions.setAlphabetKeyboard(); + } + break; + case SHIFT_LOCK_SHIFTED: + mAlphabetShiftState.setShifted(true); + mSwitchActions.setAlphabetShiftLockShiftedKeyboard(); + break; + } + } + + private void setShiftLocked(boolean shiftLocked) { + if (DEBUG_ACTION) { + Log.d(TAG, "setShiftLocked: shiftLocked=" + shiftLocked + " " + this); + } + if (!mIsAlphabetMode) return; + if (shiftLocked && (!mAlphabetShiftState.isShiftLocked() + || mAlphabetShiftState.isShiftLockShifted())) { + mSwitchActions.setAlphabetShiftLockedKeyboard(); + } + if (!shiftLocked && mAlphabetShiftState.isShiftLocked()) { + mSwitchActions.setAlphabetKeyboard(); + } + mAlphabetShiftState.setShiftLocked(shiftLocked); + } + + private void toggleAlphabetAndSymbols() { + if (DEBUG_ACTION) { + Log.d(TAG, "toggleAlphabetAndSymbols: " + this); + } + if (mIsAlphabetMode) { + mPrevMainKeyboardWasShiftLocked = mAlphabetShiftState.isShiftLocked(); + if (mPrevSymbolsKeyboardWasShifted) { + setSymbolsShiftedKeyboard(); + } else { + setSymbolsKeyboard(); + } + mPrevSymbolsKeyboardWasShifted = false; + } else { + mPrevSymbolsKeyboardWasShifted = mIsSymbolShifted; + setAlphabetKeyboard(); + if (mPrevMainKeyboardWasShiftLocked) { + setShiftLocked(true); + } + mPrevMainKeyboardWasShiftLocked = false; + } + } + + private void toggleShiftInSymbols() { + if (mIsSymbolShifted) { + setSymbolsKeyboard(); + } else { + setSymbolsShiftedKeyboard(); + } + } + + private void setAlphabetKeyboard() { + if (DEBUG_ACTION) { + Log.d(TAG, "setAlphabetKeyboard"); + } + mSwitchActions.setAlphabetKeyboard(); + mIsAlphabetMode = true; + mIsSymbolShifted = false; + mSwitchState = SWITCH_STATE_ALPHA; + mSwitchActions.requestUpdatingShiftState(); + } + + private void setSymbolsKeyboard() { + if (DEBUG_ACTION) { + Log.d(TAG, "setSymbolsKeyboard"); + } + mSwitchActions.setSymbolsKeyboard(); + mIsAlphabetMode = false; + mIsSymbolShifted = false; + // Reset alphabet shift state. + mAlphabetShiftState.setShiftLocked(false); + mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; + } + + private void setSymbolsShiftedKeyboard() { + if (DEBUG_ACTION) { + Log.d(TAG, "setSymbolsShiftedKeyboard"); + } + mSwitchActions.setSymbolsShiftedKeyboard(); + mIsAlphabetMode = false; + mIsSymbolShifted = true; + // Reset alphabet shift state. + mAlphabetShiftState.setShiftLocked(false); + mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; + } + + public void onPressKey(int code) { + if (DEBUG_EVENT) { + Log.d(TAG, "onPressKey: code=" + Keyboard.printableCode(code) + " " + this); + } + if (code == Keyboard.CODE_SHIFT) { + onPressShift(); + } else if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { + onPressSymbol(); + } else { + mShiftKeyState.onOtherKeyPressed(); + mSymbolKeyState.onOtherKeyPressed(); + } + } + + public void onReleaseKey(int code, boolean withSliding) { + if (DEBUG_EVENT) { + Log.d(TAG, "onReleaseKey: code=" + Keyboard.printableCode(code) + + " sliding=" + withSliding + " " + this); + } + if (code == Keyboard.CODE_SHIFT) { + onReleaseShift(withSliding); + } else if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { + onReleaseSymbol(withSliding); + } + } + + private void onPressSymbol() { + toggleAlphabetAndSymbols(); + mSymbolKeyState.onPress(); + mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL; + } + + private void onReleaseSymbol(boolean withSliding) { + if (mSymbolKeyState.isChording()) { + // Switch back to the previous keyboard mode if the user chords the mode change key and + // another key, then releases the mode change key. + toggleAlphabetAndSymbols(); + } else if (!withSliding) { + // If the mode change key is being released without sliding, we should forget the + // previous symbols keyboard shift state and simply switch back to symbols layout + // (never symbols shifted) next time the mode gets changed to symbols layout. + mPrevSymbolsKeyboardWasShifted = false; + } + mSymbolKeyState.onRelease(); + } + + public void onLongPressTimeout(int code) { + if (DEBUG_EVENT) { + Log.d(TAG, "onLongPressTimeout: code=" + Keyboard.printableCode(code) + " " + this); + } + if (mIsAlphabetMode && code == Keyboard.CODE_SHIFT) { + if (mAlphabetShiftState.isShiftLocked()) { + setShiftLocked(false); + // Shift key is long pressed while shift locked state, we will toggle back to normal + // state. And mark as if shift key is released. + mShiftKeyState.onRelease(); + } else { + // Shift key is long pressed while shift unloked state. + setShiftLocked(true); + } + mSwitchActions.hapticAndAudioFeedback(code); + } + } + + public void onUpdateShiftState(boolean autoCaps) { + if (DEBUG_EVENT) { + Log.d(TAG, "onUpdateShiftState: autoCaps=" + autoCaps + " " + this); + } + updateAlphabetShiftState(autoCaps); + } + + private void updateAlphabetShiftState(boolean autoCaps) { + if (!mIsAlphabetMode) return; + if (!mAlphabetShiftState.isShiftLocked() && !mShiftKeyState.isIgnoring()) { + if (mShiftKeyState.isReleasing() && autoCaps) { + // Only when shift key is releasing, automatic temporary upper case will be set. + setShifted(AUTOMATIC_SHIFT); + } else { + setShifted(mShiftKeyState.isChording() ? MANUAL_SHIFT : UNSHIFT); + } + } + } + + private void onPressShift() { + if (mIsAlphabetMode) { + mIsInDoubleTapShiftKey = mSwitchActions.isInDoubleTapTimeout(); + if (!mIsInDoubleTapShiftKey) { + // This is first tap. + mSwitchActions.startDoubleTapTimer(); + } + if (mIsInDoubleTapShiftKey) { + if (mAlphabetShiftState.isManualShifted() || mIsInAlphabetUnshiftedFromShifted) { + // Shift key has been double tapped while in manual shifted or automatic + // shifted state. + setShiftLocked(true); + } else { + // Shift key has been double tapped while in normal state. This is the second + // tap to disable shift locked state, so just ignore this. + } + } else { + if (mAlphabetShiftState.isShiftLocked()) { + // Shift key is pressed while shift locked state, we will treat this state as + // shift lock shifted state and mark as if shift key pressed while normal state. + setShifted(SHIFT_LOCK_SHIFTED); + mShiftKeyState.onPress(); + } else if (mAlphabetShiftState.isAutomaticShifted()) { + // Shift key is pressed while automatic shifted, we have to move to manual + // shifted. + setShifted(MANUAL_SHIFT); + mShiftKeyState.onPress(); + } else if (mAlphabetShiftState.isShiftedOrShiftLocked()) { + // In manual shifted state, we just record shift key has been pressing while + // shifted state. + mShiftKeyState.onPressOnShifted(); + } else { + // In base layout, chording or manual shifted mode is started. + setShifted(MANUAL_SHIFT); + mShiftKeyState.onPress(); + } + mSwitchActions.startLongPressTimer(Keyboard.CODE_SHIFT); + } + } else { + // In symbol mode, just toggle symbol and symbol more keyboard. + toggleShiftInSymbols(); + mSwitchState = SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE; + mShiftKeyState.onPress(); + } + } + + private void onReleaseShift(boolean withSliding) { + if (mIsAlphabetMode) { + final boolean isShiftLocked = mAlphabetShiftState.isShiftLocked(); + mIsInAlphabetUnshiftedFromShifted = false; + if (mIsInDoubleTapShiftKey) { + // Double tap shift key has been handled in {@link #onPressShift}, so that just + // ignore this release shift key here. + mIsInDoubleTapShiftKey = false; + } else if (mShiftKeyState.isChording()) { + if (mAlphabetShiftState.isShiftLockShifted()) { + // After chording input while shift locked state. + setShiftLocked(true); + } else { + // After chording input while normal state. + setShifted(UNSHIFT); + } + } else if (mAlphabetShiftState.isShiftLockShifted() && withSliding) { + // In shift locked state, shift has been pressed and slid out to other key. + setShiftLocked(true); + } else if (isShiftLocked && !mAlphabetShiftState.isShiftLockShifted() + && (mShiftKeyState.isPressing() || mShiftKeyState.isPressingOnShifted()) + && !withSliding) { + // Shift has been long pressed, ignore this release. + } else if (isShiftLocked && !mShiftKeyState.isIgnoring() && !withSliding) { + // Shift has been pressed without chording while shift locked state. + setShiftLocked(false); + } else if (mAlphabetShiftState.isShiftedOrShiftLocked() + && mShiftKeyState.isPressingOnShifted() && !withSliding) { + // Shift has been pressed without chording while shifted state. + setShifted(UNSHIFT); + mIsInAlphabetUnshiftedFromShifted = true; + } else if (mAlphabetShiftState.isManualShiftedFromAutomaticShifted() + && mShiftKeyState.isPressing() && !withSliding) { + // Shift has been pressed without chording while manual shifted transited from + // automatic shifted + setShifted(UNSHIFT); + mIsInAlphabetUnshiftedFromShifted = true; + } + } else { + // In symbol mode, switch back to the previous keyboard mode if the user chords the + // shift key and another key, then releases the shift key. + if (mShiftKeyState.isChording()) { + toggleShiftInSymbols(); + } + } + mShiftKeyState.onRelease(); + } + + public void onCancelInput(boolean isSinglePointer) { + if (DEBUG_EVENT) { + Log.d(TAG, "onCancelInput: single=" + isSinglePointer + " " + this); + } + // Switch back to the previous keyboard mode if the user cancels sliding input. + if (isSinglePointer) { + if (mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL) { + toggleAlphabetAndSymbols(); + } else if (mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE) { + toggleShiftInSymbols(); + } + } + } + + public boolean isInMomentarySwitchState() { + return mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL + || mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE; + } + + private static boolean isSpaceCharacter(int c) { + return c == Keyboard.CODE_SPACE || c == Keyboard.CODE_ENTER; + } + + private boolean isLayoutSwitchBackCharacter(int c) { + if (TextUtils.isEmpty(mLayoutSwitchBackSymbols)) return false; + if (mLayoutSwitchBackSymbols.indexOf(c) >= 0) return true; + return false; + } + + public void onCodeInput(int code, boolean isSinglePointer, boolean autoCaps) { + if (DEBUG_EVENT) { + Log.d(TAG, "onCodeInput: code=" + Keyboard.printableCode(code) + + " single=" + isSinglePointer + + " autoCaps=" + autoCaps + " " + this); + } + + switch (mSwitchState) { + case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL: + if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { + // Detected only the mode change key has been pressed, and then released. + if (mIsAlphabetMode) { + mSwitchState = SWITCH_STATE_ALPHA; + } else { + mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; + } + } else if (isSinglePointer) { + // Switch 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, switching back to the previous keyboard + // mode is handled by {@link #onCancelInput}. + toggleAlphabetAndSymbols(); + } + break; + case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE: + 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 (isSinglePointer) { + // Switch 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. + toggleShiftInSymbols(); + mSwitchState = SWITCH_STATE_SYMBOL; + } + break; + case SWITCH_STATE_SYMBOL_BEGIN: + if (!isSpaceCharacter(code) && (Keyboard.isLetterCode(code) + || code == Keyboard.CODE_OUTPUT_TEXT)) { + mSwitchState = SWITCH_STATE_SYMBOL; + } + // Switch back to alpha keyboard mode immediately if user types a quote character. + if (isLayoutSwitchBackCharacter(code)) { + toggleAlphabetAndSymbols(); + } + break; + case SWITCH_STATE_SYMBOL: + // Switch 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)) { + toggleAlphabetAndSymbols(); + } + break; + } + + // If the code is a letter, update keyboard shift state. + if (Keyboard.isLetterCode(code)) { + updateAlphabetShiftState(autoCaps); + } + } + + private static String shiftModeToString(int shiftMode) { + switch (shiftMode) { + case UNSHIFT: return "UNSHIFT"; + case MANUAL_SHIFT: return "MANUAL"; + case AUTOMATIC_SHIFT: return "AUTOMATIC"; + default: return null; + } + } + + private static String switchStateToString(int switchState) { + switch (switchState) { + case SWITCH_STATE_ALPHA: return "ALPHA"; + case SWITCH_STATE_SYMBOL_BEGIN: return "SYMBOL-BEGIN"; + case SWITCH_STATE_SYMBOL: return "SYMBOL"; + case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL: return "MOMENTARY-ALPHA-SYMBOL"; + case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE: return "MOMENTARY-SYMBOL-MORE"; + default: return null; + } + } + + @Override + public String toString() { + return "[keyboard=" + (mIsAlphabetMode ? mAlphabetShiftState.toString() + : (mIsSymbolShifted ? "SYMBOLS_SHIFTED" : "SYMBOLS")) + + " shift=" + mShiftKeyState + + " symbol=" + mSymbolKeyState + + " switch=" + switchStateToString(mSwitchState) + "]"; + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/ModifierKeyState.java b/java/src/com/android/inputmethod/keyboard/internal/ModifierKeyState.java index dae73c4e4..b39b97720 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/ModifierKeyState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/ModifierKeyState.java @@ -18,15 +18,13 @@ package com.android.inputmethod.keyboard.internal; import android.util.Log; -import com.android.inputmethod.keyboard.KeyboardSwitcher; - -public class ModifierKeyState { - protected static final String TAG = "ModifierKeyState"; - protected static final boolean DEBUG = KeyboardSwitcher.DEBUG_STATE; +/* package */ class ModifierKeyState { + protected static final String TAG = ModifierKeyState.class.getSimpleName(); + protected static final boolean DEBUG = false; protected static final int RELEASING = 0; protected static final int PRESSING = 1; - protected static final int MOMENTARY = 2; + protected static final int CHORDING = 2; protected final String mName; protected int mState = RELEASING; @@ -52,7 +50,7 @@ public class ModifierKeyState { public void onOtherKeyPressed() { final int oldState = mState; if (oldState == PRESSING) - mState = MOMENTARY; + mState = CHORDING; if (DEBUG) Log.d(TAG, mName + ".onOtherKeyPressed: " + toString(oldState) + " > " + this); } @@ -65,8 +63,8 @@ public class ModifierKeyState { return mState == RELEASING; } - public boolean isMomentary() { - return mState == MOMENTARY; + public boolean isChording() { + return mState == CHORDING; } @Override @@ -78,7 +76,7 @@ public class ModifierKeyState { switch (state) { case RELEASING: return "RELEASING"; case PRESSING: return "PRESSING"; - case MOMENTARY: return "MOMENTARY"; + case CHORDING: return "CHORDING"; default: return "UNKNOWN"; } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpecParser.java deleted file mode 100644 index a490b0ad6..000000000 --- a/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpecParser.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.keyboard.internal; - -import android.content.res.Resources; -import android.text.TextUtils; -import android.util.Log; - -import com.android.inputmethod.keyboard.Keyboard; -import com.android.inputmethod.latin.R; - -import java.util.ArrayList; - -/** - * String parser of moreKeys attribute of Key. - * The string is comma separated texts each of which represents one "more key". - * Each "more key" specification is one of the following: - * - A single letter (Letter) - * - Label optionally followed by keyOutputText or code (keyLabel|keyOutputText). - * - Icon followed by keyOutputText or code (@icon/icon_number|@integer/key_code) - * Special character, comma ',' backslash '\', and bar '|' can be escaped by '\' - * character. - * Note that the character '@' and '\' are also parsed by XML parser and CSV parser as well. - * See {@link KeyboardIconsSet} about icon_number. - */ -public class MoreKeySpecParser { - private static final String TAG = MoreKeySpecParser.class.getSimpleName(); - - private static final char ESCAPE = '\\'; - private static final String LABEL_END = "|"; - private static final String PREFIX_AT = "@"; - private static final String PREFIX_ICON = PREFIX_AT + "icon/"; - private static final String PREFIX_CODE = PREFIX_AT + "integer/"; - - private MoreKeySpecParser() { - // Intentional empty constructor for utility class. - } - - private static boolean hasIcon(String moreKeySpec) { - if (moreKeySpec.startsWith(PREFIX_ICON)) { - final int end = indexOfLabelEnd(moreKeySpec, 0); - if (end > 0) - return true; - throw new MoreKeySpecParserError("outputText or code not specified: " + moreKeySpec); - } - return false; - } - - private static boolean hasCode(String moreKeySpec) { - final int end = indexOfLabelEnd(moreKeySpec, 0); - if (end > 0 && end + 1 < moreKeySpec.length() - && moreKeySpec.substring(end + 1).startsWith(PREFIX_CODE)) { - return true; - } - return false; - } - - private static String parseEscape(String text) { - if (text.indexOf(ESCAPE) < 0) - return text; - final int length = text.length(); - final StringBuilder sb = new StringBuilder(); - for (int pos = 0; pos < length; pos++) { - final char c = text.charAt(pos); - if (c == ESCAPE && pos + 1 < length) { - sb.append(text.charAt(++pos)); - } else { - sb.append(c); - } - } - return sb.toString(); - } - - private static int indexOfLabelEnd(String moreKeySpec, int start) { - if (moreKeySpec.indexOf(ESCAPE, start) < 0) { - final int end = moreKeySpec.indexOf(LABEL_END, start); - if (end == 0) - throw new MoreKeySpecParserError(LABEL_END + " at " + start + ": " + moreKeySpec); - return end; - } - final int length = moreKeySpec.length(); - for (int pos = start; pos < length; pos++) { - final char c = moreKeySpec.charAt(pos); - if (c == ESCAPE && pos + 1 < length) { - pos++; - } else if (moreKeySpec.startsWith(LABEL_END, pos)) { - return pos; - } - } - return -1; - } - - public static String getLabel(String moreKeySpec) { - if (hasIcon(moreKeySpec)) - return null; - final int end = indexOfLabelEnd(moreKeySpec, 0); - final String label = (end > 0) ? parseEscape(moreKeySpec.substring(0, end)) - : parseEscape(moreKeySpec); - if (TextUtils.isEmpty(label)) - throw new MoreKeySpecParserError("Empty label: " + moreKeySpec); - return label; - } - - public static String getOutputText(String moreKeySpec) { - if (hasCode(moreKeySpec)) - return null; - final int end = indexOfLabelEnd(moreKeySpec, 0); - if (end > 0) { - if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) - throw new MoreKeySpecParserError("Multiple " + LABEL_END + ": " - + moreKeySpec); - final String outputText = parseEscape(moreKeySpec.substring(end + LABEL_END.length())); - if (!TextUtils.isEmpty(outputText)) - return outputText; - throw new MoreKeySpecParserError("Empty outputText: " + moreKeySpec); - } - final String label = getLabel(moreKeySpec); - if (label == null) - throw new MoreKeySpecParserError("Empty label: " + moreKeySpec); - // Code is automatically generated for one letter label. See {@link getCode()}. - if (label.length() == 1) - return null; - return label; - } - - public static int getCode(Resources res, String moreKeySpec) { - if (hasCode(moreKeySpec)) { - final int end = indexOfLabelEnd(moreKeySpec, 0); - if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) - throw new MoreKeySpecParserError("Multiple " + LABEL_END + ": " + moreKeySpec); - final int resId = getResourceId(res, - moreKeySpec.substring(end + LABEL_END.length() + PREFIX_AT.length())); - final int code = res.getInteger(resId); - return code; - } - if (indexOfLabelEnd(moreKeySpec, 0) > 0) - return Keyboard.CODE_DUMMY; - final String label = getLabel(moreKeySpec); - // Code is automatically generated for one letter label. - if (label != null && label.length() == 1) - return label.charAt(0); - return Keyboard.CODE_DUMMY; - } - - public static int getIconId(String moreKeySpec) { - if (hasIcon(moreKeySpec)) { - int end = moreKeySpec.indexOf(LABEL_END, PREFIX_ICON.length() + 1); - final String iconId = moreKeySpec.substring(PREFIX_ICON.length(), end); - try { - return Integer.valueOf(iconId); - } catch (NumberFormatException e) { - Log.w(TAG, "illegal icon id specified: " + iconId); - return KeyboardIconsSet.ICON_UNDEFINED; - } - } - return KeyboardIconsSet.ICON_UNDEFINED; - } - - private static int getResourceId(Resources res, String name) { - String packageName = res.getResourcePackageName(R.string.english_ime_name); - int resId = res.getIdentifier(name, null, packageName); - if (resId == 0) - throw new MoreKeySpecParserError("Unknown resource: " + name); - return resId; - } - - @SuppressWarnings("serial") - public static class MoreKeySpecParserError extends RuntimeException { - public MoreKeySpecParserError(String message) { - super(message); - } - } - - public interface CodeFilter { - public boolean shouldFilterOut(int code); - } - - public static final CodeFilter DIGIT_FILTER = new CodeFilter() { - @Override - public boolean shouldFilterOut(int code) { - return Character.isDigit(code); - } - }; - - public static CharSequence[] filterOut(Resources res, CharSequence[] moreKeys, - CodeFilter filter) { - if (moreKeys == null || moreKeys.length < 1) { - return null; - } - if (moreKeys.length == 1 - && filter.shouldFilterOut(getCode(res, moreKeys[0].toString()))) { - return null; - } - ArrayList<CharSequence> filtered = null; - for (int i = 0; i < moreKeys.length; i++) { - final CharSequence moreKeySpec = moreKeys[i]; - if (filter.shouldFilterOut(getCode(res, moreKeySpec.toString()))) { - if (filtered == null) { - filtered = new ArrayList<CharSequence>(); - for (int j = 0; j < i; j++) { - filtered.add(moreKeys[j]); - } - } - } else if (filtered != null) { - filtered.add(moreKeySpec); - } - } - if (filtered == null) { - return moreKeys; - } - if (filtered.size() == 0) { - return null; - } - return filtered.toArray(new CharSequence[filtered.size()]); - } -} 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..edb40c8e7 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; @@ -30,7 +30,7 @@ public class ShiftKeyState extends ModifierKeyState { public void onOtherKeyPressed() { int oldState = mState; if (oldState == PRESSING) { - mState = MOMENTARY; + mState = CHORDING; } else if (oldState == PRESSING_ON_SHIFTED) { mState = IGNORING; } diff --git a/java/src/com/android/inputmethod/latin/AutoCorrection.java b/java/src/com/android/inputmethod/latin/AutoCorrection.java index 485ec511f..bcb78919d 100644 --- a/java/src/com/android/inputmethod/latin/AutoCorrection.java +++ b/java/src/com/android/inputmethod/latin/AutoCorrection.java @@ -74,6 +74,14 @@ public class AutoCorrection { for (final String key : dictionaries.keySet()) { if (key.equals(Suggest.DICT_KEY_WHITELIST)) continue; final Dictionary dictionary = dictionaries.get(key); + // It's unclear how realistically 'dictionary' can be null, but the monkey is somehow + // managing to get null in here. Presumably the language is changing to a language with + // no main dictionary and the monkey manages to type a whole word before the thread + // that reads the dictionary is started or something? + // Ideally the passed map would come out of a {@link java.util.concurrent.Future} and + // would be immutable once it's finished initializing, but concretely a null test is + // probably good enough for the time being. + if (null == dictionary) continue; if (dictionary.isValidWord(word) || (ignoreCase && dictionary.isValidWord(lowerCasedWord))) { return true; @@ -98,7 +106,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; @@ -118,8 +126,9 @@ public class AutoCorrection { final int autoCorrectionSuggestionScore = sortedScores[0]; // TODO: when the normalized score of the first suggestion is nearly equals to // the normalized score of the second suggestion, behave less aggressive. - mNormalizedScore = Utils.calcNormalizedScore( - typedWord,autoCorrectionSuggestion, autoCorrectionSuggestionScore); + mNormalizedScore = BinaryDictionary.calcNormalizedScore( + typedWord.toString(), autoCorrectionSuggestion.toString(), + autoCorrectionSuggestionScore); if (DBG) { Log.d(TAG, "Normalized " + typedWord + "," + autoCorrectionSuggestion + "," + autoCorrectionSuggestionScore + ", " + mNormalizedScore diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index b9fd57434..b82400046 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,17 +107,21 @@ 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); + private static native double calcNormalizedScoreNative( + char[] before, int beforeLength, char[] after, int afterLength, int score); + private static native int editDistanceNative( + char[] before, int beforeLength, char[] after, int afterLength); private final void loadDictionary(String path, long startOffset, long length) { mNativeDict = openNative(path, startOffset, length, @@ -158,7 +162,7 @@ public class BinaryDictionary extends Dictionary { } if (len > 0) { callback.addWord(mOutputChars_bigrams, start, len, mBigramScores[j], - mDicTypeId, DataType.BIGRAM); + mDicTypeId, Dictionary.BIGRAM); } } } @@ -178,7 +182,7 @@ public class BinaryDictionary extends Dictionary { } if (len > 0) { callback.addWord(mOutputChars, start, len, mScores[j], mDicTypeId, - DataType.UNIGRAM); + Dictionary.UNIGRAM); } } } @@ -211,6 +215,16 @@ public class BinaryDictionary extends Dictionary { mFlags, outputChars, scores); } + public static double calcNormalizedScore(String before, String after, int score) { + return calcNormalizedScoreNative(before.toCharArray(), before.length(), + after.toCharArray(), after.length(), score); + } + + public static int editDistance(String before, String after) { + return editDistanceNative( + before.toCharArray(), before.length(), after.toCharArray(), after.length()); + } + @Override public boolean isValidWord(CharSequence word) { if (word == null) return false; diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java index b333e4873..79441c557 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java @@ -75,7 +75,8 @@ class BinaryDictionaryGetter { // This assumes '%' is fully available as a non-separator, normal // character in a file name. This is probably true for all file systems. final StringBuilder sb = new StringBuilder(); - for (int i = 0; i < name.length(); ++i) { + final int nameLength = name.length(); + for (int i = 0; i < nameLength; i = name.offsetByCodePoints(i, 1)) { final int codePoint = name.codePointAt(i); if (isFileNameCharacter(codePoint)) { sb.appendCodePoint(codePoint); @@ -92,7 +93,8 @@ class BinaryDictionaryGetter { */ private static String getWordListIdFromFileName(final String fname) { final StringBuilder sb = new StringBuilder(); - for (int i = 0; i < fname.length(); ++i) { + final int fnameLength = fname.length(); + for (int i = 0; i < fnameLength; i = fname.offsetByCodePoints(i, 1)) { final int codePoint = fname.codePointAt(i); if ('%' != codePoint) { sb.appendCodePoint(codePoint); diff --git a/java/src/com/android/inputmethod/latin/ComposingStateManager.java b/java/src/com/android/inputmethod/latin/ComposingStateManager.java index 8811f2023..27f509a29 100644 --- a/java/src/com/android/inputmethod/latin/ComposingStateManager.java +++ b/java/src/com/android/inputmethod/latin/ComposingStateManager.java @@ -53,6 +53,13 @@ public class ComposingStateManager { } } + public synchronized boolean isComposing() { + // TODO: use the composing flag in WordComposer instead of maintaining it + // here separately. Even better, do away with this class and manage the auto + // correction indicator in the same place as the suggestions. + return mIsComposing; + } + public synchronized boolean isAutoCorrectionIndicatorOn() { return mAutoCorrectionIndicatorOn; } diff --git a/java/src/com/android/inputmethod/latin/DebugSettings.java b/java/src/com/android/inputmethod/latin/DebugSettings.java index 2f1e7c2b8..3805da154 100644 --- a/java/src/com/android/inputmethod/latin/DebugSettings.java +++ b/java/src/com/android/inputmethod/latin/DebugSettings.java @@ -30,6 +30,7 @@ public class DebugSettings extends PreferenceActivity private static final String TAG = "DebugSettings"; private static final String DEBUG_MODE_KEY = "debug_mode"; + public static final String FORCE_NON_DISTINCT_MULTITOUCH_KEY = "force_non_distinct_multitouch"; private boolean mServiceNeedsRestart = false; private CheckBoxPreference mDebugMode; @@ -60,6 +61,8 @@ public class DebugSettings extends PreferenceActivity updateDebugMode(); mServiceNeedsRestart = true; } + } else if (key.equals(FORCE_NON_DISTINCT_MULTITOUCH_KEY)) { + mServiceNeedsRestart = true; } } diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index c35b42877..79bf33850 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -33,9 +33,8 @@ public abstract class Dictionary { */ protected static final int FULL_WORD_SCORE_MULTIPLIER = 2; - public static enum DataType { - UNIGRAM, BIGRAM - } + public static final int UNIGRAM = 0; + public static final int BIGRAM = 1; /** * Interface to be implemented by classes requesting words to be fetched from the dictionary. @@ -51,11 +50,11 @@ public abstract class Dictionary { * @param score the score of occurrence. This is normalized between 1 and 255, but * can exceed those limits * @param dicTypeId of the dictionary where word was from - * @param dataType tells type of this data + * @param dataType tells type of this data, either UNIGRAM or BIGRAM * @return true if the word was added, false if no more words are required */ boolean addWord(char[] word, int wordOffset, int wordLength, int score, int dicTypeId, - DataType dataType); + int dataType); } /** @@ -64,7 +63,7 @@ public abstract class Dictionary { * @param composer the key sequence to match * @param callback the callback object to send matched words to as possible candidates * @param proximityInfo the object for key proximity. May be ignored by some implementations. - * @see WordCallback#addWord(char[], int, int, int, int, DataType) + * @see WordCallback#addWord(char[], int, int, int, int, int) */ abstract public void getWords(final WordComposer composer, final WordCallback callback, final ProximityInfo proximityInfo); 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/EditingUtils.java b/java/src/com/android/inputmethod/latin/EditingUtils.java index 634dbbdfc..1e8ad1840 100644 --- a/java/src/com/android/inputmethod/latin/EditingUtils.java +++ b/java/src/com/android/inputmethod/latin/EditingUtils.java @@ -87,23 +87,6 @@ public class EditingUtils { } /** - * Removes the word surrounding the cursor. Parameters are identical to - * getWordAtCursor. - */ - public static void deleteWordAtCursor(InputConnection connection, String separators) { - // getWordRangeAtCursor returns null if the connection is null - Range range = getWordRangeAtCursor(connection, separators); - if (range == null) return; - - connection.finishComposingText(); - // Move cursor to beginning of word, to avoid crash when cursor is outside - // of valid range after deleting text. - int newCursor = getCursorPosition(connection) - range.mCharsBefore; - connection.setSelection(newCursor, newCursor); - connection.deleteSurroundingText(0, range.mCharsBefore + range.mCharsAfter); - } - - /** * Represents a range of text, relative to the current cursor position. */ public static class Range { diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index cad69bb0e..8e8adc1c2 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -51,6 +51,7 @@ public class ExpandableDictionary extends Dictionary { private Object mUpdatingLock = new Object(); private static class Node { + Node() {} char mCode; int mFrequency; boolean mTerminal; @@ -300,7 +301,7 @@ public class ExpandableDictionary extends Dictionary { finalFreq = computeSkippedWordFinalFreq(freq, snr, mInputLength); } if (!callback.addWord(word, 0, depth + 1, finalFreq, mDicTypeId, - DataType.UNIGRAM)) { + Dictionary.UNIGRAM)) { return; } } @@ -341,7 +342,7 @@ public class ExpandableDictionary extends Dictionary { snr * addedAttenuation, mInputLength); } callback.addWord(word, 0, depth + 1, finalFreq, mDicTypeId, - DataType.UNIGRAM); + Dictionary.UNIGRAM); } } if (children != null) { @@ -505,7 +506,7 @@ public class ExpandableDictionary extends Dictionary { } while (node != null); callback.addWord(mLookedUpString, index, MAX_WORD_LENGTH - index, freq, mDicTypeId, - DataType.BIGRAM); + Dictionary.BIGRAM); } } @@ -547,6 +548,7 @@ public class ExpandableDictionary extends Dictionary { } private class LoadDictionaryTask extends Thread { + LoadDictionaryTask() {} @Override public void run() { loadDictionaryAsync(); diff --git a/java/src/com/android/inputmethod/latin/InputAttributes.java b/java/src/com/android/inputmethod/latin/InputAttributes.java new file mode 100644 index 000000000..3de5c1d48 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/InputAttributes.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin; + +import android.text.InputType; +import android.util.Log; +import android.view.inputmethod.EditorInfo; + +import com.android.inputmethod.compat.InputTypeCompatUtils; + +/** + * Class to hold attributes of the input field. + */ +public class InputAttributes { + private final String TAG = InputAttributes.class.getSimpleName(); + + final public boolean mInputTypeNoAutoCorrect; + final public boolean mIsSettingsSuggestionStripOn; + final public boolean mApplicationSpecifiedCompletionOn; + + public InputAttributes(final EditorInfo editorInfo, final boolean isFullscreenMode) { + final int inputType = null != editorInfo ? editorInfo.inputType : 0; + final int inputClass = inputType & InputType.TYPE_MASK_CLASS; + if (inputClass != InputType.TYPE_CLASS_TEXT) { + // If we are not looking at a TYPE_CLASS_TEXT field, the following strange + // cases may arise, so we do a couple sanity checks for them. If it's a + // TYPE_CLASS_TEXT field, these special cases cannot happen, by construction + // of the flags. + if (null == editorInfo) { + Log.w(TAG, "No editor info for this field. Bug?"); + } else if (InputType.TYPE_NULL == inputType) { + // TODO: We should honor TYPE_NULL specification. + Log.i(TAG, "InputType.TYPE_NULL is specified"); + } else if (inputClass == 0) { + // TODO: is this check still necessary? + Log.w(TAG, String.format("Unexpected input class: inputType=0x%08x" + + " imeOptions=0x%08x", + inputType, editorInfo.imeOptions)); + } + mIsSettingsSuggestionStripOn = false; + mInputTypeNoAutoCorrect = false; + mApplicationSpecifiedCompletionOn = false; + } else { + final int variation = inputType & InputType.TYPE_MASK_VARIATION; + final boolean flagNoSuggestions = + 0 != (inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); + final boolean flagMultiLine = + 0 != (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE); + final boolean flagAutoCorrect = + 0 != (inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); + final boolean flagAutoComplete = + 0 != (inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE); + + // Make sure that passwords are not displayed in {@link SuggestionsView}. + if (InputTypeCompatUtils.isPasswordInputType(inputType) + || InputTypeCompatUtils.isVisiblePasswordInputType(inputType) + || InputTypeCompatUtils.isEmailVariation(variation) + || InputType.TYPE_TEXT_VARIATION_URI == variation + || InputType.TYPE_TEXT_VARIATION_FILTER == variation + || flagNoSuggestions + || flagAutoComplete) { + mIsSettingsSuggestionStripOn = false; + } else { + mIsSettingsSuggestionStripOn = true; + } + + // If it's a browser edit field and auto correct is not ON explicitly, then + // disable auto correction, but keep suggestions on. + // If NO_SUGGESTIONS is set, don't do prediction. + // If it's not multiline and the autoCorrect flag is not set, then don't correct + if ((variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT + && !flagAutoCorrect) + || flagNoSuggestions + || (!flagAutoCorrect && !flagMultiLine)) { + mInputTypeNoAutoCorrect = true; + } else { + mInputTypeNoAutoCorrect = false; + } + + mApplicationSpecifiedCompletionOn = flagAutoComplete && isFullscreenMode; + } + } + + // Pretty print + @Override + public String toString() { + return "\n mInputTypeNoAutoCorrect = " + mInputTypeNoAutoCorrect + + "\n mIsSettingsSuggestionStripOn = " + mIsSettingsSuggestionStripOn + + "\n mApplicationSpecifiedCompletionOn = " + mApplicationSpecifiedCompletionOn; + } +} diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java new file mode 100644 index 000000000..f34cb5ff9 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin; + +import android.text.TextUtils; + +import java.util.ArrayList; + +/** + * This class encapsulates data about a word previously composed, but that has been + * committed already. This is used for resuming suggestion, and cancel auto-correction. + */ +public class LastComposedWord { + // COMMIT_TYPE_USER_TYPED_WORD is used when the word committed is the exact typed word, with + // no hinting from the IME. It happens when some external event happens (rotating the device, + // for example) or when auto-correction is off by settings or editor attributes. + public static final int COMMIT_TYPE_USER_TYPED_WORD = 0; + // COMMIT_TYPE_MANUAL_PICK is used when the user pressed a field in the suggestion strip. + public static final int COMMIT_TYPE_MANUAL_PICK = 1; + // COMMIT_TYPE_DECIDED_WORD is used when the IME commits the word it decided was best + // for the current user input. It may be different from what the user typed (true auto-correct) + // or it may be exactly what the user typed if it's in the dictionary or the IME does not have + // enough confidence in any suggestion to auto-correct (auto-correct to typed word). + public static final int COMMIT_TYPE_DECIDED_WORD = 2; + // COMMIT_TYPE_CANCEL_AUTO_CORRECT is used upon committing back the old word upon cancelling + // an auto-correction. + public static final int COMMIT_TYPE_CANCEL_AUTO_CORRECT = 3; + + public final ArrayList<int[]> mCodes; + public final int[] mXCoordinates; + public final int[] mYCoordinates; + public final String mTypedWord; + public final String mAutoCorrection; + + private boolean mActive; + + public static final LastComposedWord NOT_A_COMPOSED_WORD = + new LastComposedWord(null, null, null, "", ""); + + // Warning: this is using the passed objects as is and fully expects them to be + // immutable. Do not fiddle with their contents after you passed them to this constructor. + public LastComposedWord(final ArrayList<int[]> codes, final int[] xCoordinates, + final int[] yCoordinates, final String typedWord, final String autoCorrection) { + mCodes = codes; + mXCoordinates = xCoordinates; + mYCoordinates = yCoordinates; + mTypedWord = typedWord; + mAutoCorrection = autoCorrection; + mActive = true; + } + + public void deactivate() { + mActive = false; + } + + public boolean canCancelAutoCorrect() { + return mActive && !TextUtils.isEmpty(mAutoCorrection) + && !TextUtils.equals(mTypedWord, mAutoCorrection); + } +} diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 9c321bcb9..1cb79e707 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -49,6 +49,7 @@ import android.view.inputmethod.ExtractedText; import android.view.inputmethod.InputConnection; import com.android.inputmethod.accessibility.AccessibilityUtils; +import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; import com.android.inputmethod.compat.CompatUtils; import com.android.inputmethod.compat.EditorInfoCompatUtils; import com.android.inputmethod.compat.InputConnectionCompatUtils; @@ -59,13 +60,13 @@ import com.android.inputmethod.compat.SuggestionSpanUtils; import com.android.inputmethod.compat.VibratorCompatWrapper; import com.android.inputmethod.deprecated.LanguageSwitcherProxy; import com.android.inputmethod.deprecated.VoiceProxy; -import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardActionListener; +import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.KeyboardView; -import com.android.inputmethod.keyboard.LatinKeyboard; import com.android.inputmethod.keyboard.LatinKeyboardView; +import com.android.inputmethod.latin.suggestions.SuggestionsView; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -77,7 +78,6 @@ import java.util.Locale; public class LatinIME extends InputMethodServiceCompatWrapper implements KeyboardActionListener, SuggestionsView.Listener { private static final String TAG = LatinIME.class.getSimpleName(); - private static final boolean PERF_DEBUG = false; private static final boolean TRACE = false; private static boolean DEBUG; @@ -107,7 +107,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar /** * The private IME option used to indicate that the given text field needs * ASCII code points input. + * + * @deprecated Use {@link EditorInfo#IME_FLAG_FORCE_ASCII}. */ + @SuppressWarnings("dep-ann") public static final String IME_OPTION_FORCE_ASCII = "forceAscii"; /** @@ -143,6 +146,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar */ private static final String SCHEME_PACKAGE = "package"; + // TODO: migrate this to SettingsValues private int mSuggestionVisibility; private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE = R.string.prefs_suggestion_visibility_show_value; @@ -157,19 +161,38 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar SUGGESTION_VISIBILILTY_HIDE_VALUE }; - private Settings.Values mSettingsValues; + private static final int SPACE_STATE_NONE = 0; + // 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. + private static final int SPACE_STATE_DOUBLE = 1; + // 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_SWAP_PUNCTUATION = 2; + // Weak space: a space that should be swapped only by suggestion strip punctuation. Weak + // spaces happen when the user presses space, accepting the current suggestion (whether + // it's an auto-correction or not). + private static final int SPACE_STATE_WEAK = 3; + // Phantom space: a not-yet-inserted space that should get inserted on the next input, + // character provided it's not a separator. If it's a separator, the phantom space is dropped. + // Phantom spaces happen when a user chooses a word from the suggestion strip. + private static final int SPACE_STATE_PHANTOM = 4; + + // Current space state of the input method. This can be any of the above constants. + private int mSpaceState; + + private SettingsValues mSettingsValues; + private InputAttributes mInputAttributes; private View mExtractArea; private View mKeyPreviewBackingView; private View mSuggestionsContainer; private SuggestionsView mSuggestionsView; - private Suggest mSuggest; + /* package for tests */ Suggest mSuggest; private CompletionInfo[] mApplicationSpecifiedCompletions; private InputMethodManagerCompatWrapper mImm; private Resources mResources; private SharedPreferences mPrefs; - private String mInputMethodId; private KeyboardSwitcher mKeyboardSwitcher; private SubtypeSwitcher mSubtypeSwitcher; private VoiceProxy mVoiceProxy; @@ -177,31 +200,17 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private UserDictionary mUserDictionary; private UserBigramDictionary mUserBigramDictionary; private UserUnigramDictionary mUserUnigramDictionary; - private boolean mIsUserDictionaryAvaliable; - - // TODO: Create an inner class to group options and pseudo-options to improve readability. - // These variables are initialized according to the {@link EditorInfo#inputType}. - private boolean mInsertSpaceOnPickSuggestionManually; - private boolean mInputTypeNoAutoCorrect; - private boolean mIsSettingsSuggestionStripOn; - private boolean mApplicationSpecifiedCompletionOn; + private boolean mIsUserDictionaryAvailable; - private final StringBuilder mComposingStringBuilder = new StringBuilder(); + private LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; 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; + // Keep track of the last selection range to decide if we need to show word alternatives - private int mLastSelectionStart; - private int mLastSelectionEnd; + private static final int NOT_A_CURSOR_POSITION = -1; + private int mLastSelectionStart = NOT_A_CURSOR_POSITION; + private int mLastSelectionEnd = NOT_A_CURSOR_POSITION; // Whether we are expecting an onUpdateSelection event to fire. If it does when we don't // "expect" it, it means the user actually moved the cursor. @@ -210,11 +219,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private long mLastKeyTime; private AudioManager mAudioManager; - private float mFxVolume = -1.0f; // default volume private boolean mSilentModeOn; // System-wide current configuration private VibratorCompatWrapper mVibrator; - private long mKeypressVibrationDuration = -1; // TODO: Move this flag to VoiceProxy private boolean mConfigurationChanging; @@ -241,9 +248,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 +257,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 +276,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 @@ -291,23 +294,20 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar latinIme.updateBigramPredictions(); break; case MSG_VOICE_RESULTS: + final Keyboard keyboard = switcher.getKeyboard(); latinIme.mVoiceProxy.handleVoiceResults(latinIme.preferCapitalization() - || (switcher.isAlphabetMode() && switcher.isShiftedOrShiftLocked())); + || (keyboard != null && keyboard.isShiftedOrShiftLocked())); break; case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR: - if (inputView != null) { - inputView.setSpacebarTextFadeFactor( - (1.0f + mFinalFadeoutFactorOfLanguageOnSpacebar) / 2, - (LatinKeyboard)msg.obj); - } + setSpacebarTextFadeFactor(inputView, + (1.0f + mFinalFadeoutFactorOfLanguageOnSpacebar) / 2, + (Keyboard)msg.obj); sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj), mDurationOfFadeoutLanguageOnSpacebar); break; case MSG_DISMISS_LANGUAGE_ON_SPACEBAR: - if (inputView != null) { - inputView.setSpacebarTextFadeFactor(mFinalFadeoutFactorOfLanguageOnSpacebar, - (LatinKeyboard)msg.obj); - } + setSpacebarTextFadeFactor(inputView, mFinalFadeoutFactorOfLanguageOnSpacebar, + (Keyboard)msg.obj); break; } } @@ -347,21 +347,32 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar sendMessage(obtainMessage(MSG_VOICE_RESULTS)); } + private static void setSpacebarTextFadeFactor(LatinKeyboardView inputView, + float fadeFactor, Keyboard oldKeyboard) { + if (inputView == null) return; + final Keyboard keyboard = inputView.getKeyboard(); + if (keyboard == oldKeyboard) { + inputView.updateSpacebar(fadeFactor, + SubtypeSwitcher.getInstance().needsToDisplayLanguage( + keyboard.mId.mLocale)); + } + } + public void startDisplayLanguageOnSpacebar(boolean localeChanged) { final LatinIME latinIme = getOuterInstance(); removeMessages(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR); removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR); final LatinKeyboardView inputView = latinIme.mKeyboardSwitcher.getKeyboardView(); if (inputView != null) { - final LatinKeyboard keyboard = latinIme.mKeyboardSwitcher.getLatinKeyboard(); + final Keyboard keyboard = latinIme.mKeyboardSwitcher.getKeyboard(); // The language is always displayed when the delay is negative. final boolean needsToDisplayLanguage = localeChanged || mDelayBeforeFadeoutLanguageOnSpacebar < 0; // The language is never displayed when the delay is zero. if (mDelayBeforeFadeoutLanguageOnSpacebar != 0) { - inputView.setSpacebarTextFadeFactor(needsToDisplayLanguage ? 1.0f - : mFinalFadeoutFactorOfLanguageOnSpacebar, - keyboard); + setSpacebarTextFadeFactor(inputView, + needsToDisplayLanguage ? 1.0f : mFinalFadeoutFactorOfLanguageOnSpacebar, + keyboard); } // The fadeout animation will start when the delay is positive. if (localeChanged && mDelayBeforeFadeoutLanguageOnSpacebar > 0) { @@ -384,21 +395,13 @@ 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 mPendingSuccessiveImsCallback; private boolean mHasPendingStartInput; private boolean mHasPendingFinishInputView; private boolean mHasPendingFinishInput; + private EditorInfo mAppliedEditorInfo; public void startOrientationChanging() { removeMessages(MSG_PENDING_IMS_CALLBACK); @@ -416,18 +419,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; @@ -435,30 +438,32 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (mIsOrientationChanging && restarting) { // This is the first onStartInput after orientation changed. mIsOrientationChanging = false; - mPendingSuccesiveImsCallback = true; + mPendingSuccessiveImsCallback = 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) + && KeyboardId.equivalentEditorInfoForKeyboard(editorInfo, mAppliedEditorInfo)) { + // Typically this is the second onStartInputView after orientation changed. + resetPendingImsCallback(); + } else { + if (mPendingSuccessiveImsCallback) { + // This is the first onStartInputView after orientation changed. + mPendingSuccessiveImsCallback = 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) { @@ -468,6 +473,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } else { final LatinIME latinIme = getOuterInstance(); latinIme.onFinishInputViewInternal(finishingInput); + mAppliedEditorInfo = null; } } @@ -492,12 +498,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar InputMethodManagerCompatWrapper.init(this); SubtypeSwitcher.init(this); KeyboardSwitcher.init(this, prefs); - AccessibilityUtils.init(this, prefs); + AccessibilityUtils.init(this); super.onCreate(); mImm = InputMethodManagerCompatWrapper.getInstance(); - mInputMethodId = Utils.getInputMethodId(mImm, getPackageName()); mSubtypeSwitcher = SubtypeSwitcher.getInstance(); mKeyboardSwitcher = KeyboardSwitcher.getInstance(); mVibrator = VibratorCompatWrapper.getInstance(this); @@ -509,6 +514,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar loadSettings(); + // TODO: remove the following when it's not needed by updateCorrectionMode() any more + mInputAttributes = new InputAttributes(null, false /* isFullscreenMode */); Utils.GCUtils.getInstance().reset(); boolean tryGC = true; for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) { @@ -546,10 +553,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar /* package */ void loadSettings() { if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this); if (null == mSubtypeSwitcher) mSubtypeSwitcher = SubtypeSwitcher.getInstance(); - mSettingsValues = new Settings.Values(mPrefs, this, mSubtypeSwitcher.getInputLocaleStr()); + mSettingsValues = new SettingsValues(mPrefs, this, mSubtypeSwitcher.getInputLocaleStr()); resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary()); - updateSoundEffectVolume(); - updateKeypressVibrationDuration(); } private void initSuggest() { @@ -574,7 +579,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mUserDictionary = new UserDictionary(this, localeStr); mSuggest.setUserDictionary(mUserDictionary); - mIsUserDictionaryAvaliable = mUserDictionary.isEnabled(); + mIsUserDictionaryAvailable = mUserDictionary.isEnabled(); resetContactsDictionary(oldContactsDictionary); @@ -695,13 +700,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 @@ -714,20 +719,32 @@ 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))); + } + if (Utils.inPrivateImeOptions(null, IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo)) { + Log.w(TAG, "Deprecated private IME option specified: " + + editorInfo.privateImeOptions); + Log.w(TAG, "Use " + getPackageName() + "." + IME_OPTION_NO_MICROPHONE + " instead"); } + if (Utils.inPrivateImeOptions(getPackageName(), IME_OPTION_FORCE_ASCII, editorInfo)) { + Log.w(TAG, "Deprecated private IME option specified: " + + editorInfo.privateImeOptions); + Log.w(TAG, "Use EditorInfo.IME_FLAG_FORCE_ASCII flag instead"); + } + + LatinImeLogger.onStartInputView(editorInfo); // In landscape mode, this method gets called without the input view being created. if (inputView == null) { return; @@ -736,47 +753,44 @@ 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(); - TextEntryState.reset(); - // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to // know now whether this is a password text field, because we need to know now whether we // want to enable the voice button. final 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); + mInputAttributes = new InputAttributes(editorInfo, isFullscreenMode()); + mApplicationSpecifiedCompletions = null; inputView.closing(); mEnteredText = null; - mComposingStringBuilder.setLength(0); - mHasUncommittedTypedChars = false; + resetComposingState(true /* alsoResetLastComposedWord */); mDeleteCount = 0; - mJustAddedMagicSpace = false; - mJustReplacedDoubleSpace = false; + mSpaceState = SPACE_STATE_NONE; loadSettings(); updateCorrectionMode(); - updateSuggestionVisibility(mPrefs, mResources); + updateSuggestionVisibility(mResources); 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) @@ -785,6 +799,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); @@ -795,73 +810,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); } - private void initializeInputAttributes(EditorInfo attribute) { - if (attribute == null) - return; - final int inputType = attribute.inputType; - if (inputType == InputType.TYPE_NULL) { - // TODO: We should honor TYPE_NULL specification. - Log.i(TAG, "InputType.TYPE_NULL is specified"); - } - final int inputClass = inputType & InputType.TYPE_MASK_CLASS; - 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)); - } - - mInsertSpaceOnPickSuggestionManually = false; - mInputTypeNoAutoCorrect = false; - mIsSettingsSuggestionStripOn = false; - mApplicationSpecifiedCompletionOn = false; - mApplicationSpecifiedCompletions = null; - - if (inputClass == InputType.TYPE_CLASS_TEXT) { - mIsSettingsSuggestionStripOn = true; - // Make sure that passwords are not displayed in {@link SuggestionsView}. - if (InputTypeCompatUtils.isPasswordInputType(inputType) - || InputTypeCompatUtils.isVisiblePasswordInputType(inputType)) { - mIsSettingsSuggestionStripOn = false; - } - if (InputTypeCompatUtils.isEmailVariation(variation) - || variation == InputType.TYPE_TEXT_VARIATION_PERSON_NAME) { - // The point in turning this off is that we don't want to insert a space after - // a name when filling a form: we can't delete trailing spaces when changing fields - mInsertSpaceOnPickSuggestionManually = false; - } else { - mInsertSpaceOnPickSuggestionManually = true; - } - if (InputTypeCompatUtils.isEmailVariation(variation)) { - mIsSettingsSuggestionStripOn = false; - } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) { - mIsSettingsSuggestionStripOn = false; - } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) { - mIsSettingsSuggestionStripOn = false; - } else if (variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) { - // If it's a browser edit field and auto correct is not ON explicitly, then - // disable auto correction, but keep suggestions on. - if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) { - mInputTypeNoAutoCorrect = true; - } - } - - // If NO_SUGGESTIONS is set, don't do prediction. - if ((inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) { - mIsSettingsSuggestionStripOn = false; - mInputTypeNoAutoCorrect = true; - } - // If it's not multiline and the autoCorrect flag is not set, then don't correct - if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 - && (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) { - mInputTypeNoAutoCorrect = true; - } - if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) { - mIsSettingsSuggestionStripOn = false; - mApplicationSpecifiedCompletionOn = isFullscreenMode(); - } - } - } - @Override public void onWindowHidden() { super.onWindowHidden(); @@ -923,12 +871,20 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar || newSelEnd != candidatesEnd) && mLastSelectionStart != newSelStart; final boolean candidatesCleared = candidatesStart == -1 && candidatesEnd == -1; if (!mExpectingUpdateSelection) { - if (((mComposingStringBuilder.length() > 0 && mHasUncommittedTypedChars) + // TAKE CARE: there is a race condition when we enter this test even when the user + // did not explicitly move the cursor. This happens when typing fast, where two keys + // turn this flag on in succession and both onUpdateSelection() calls arrive after + // the second one - the first call successfully avoids this test, but the second one + // enters. For the moment we rely on candidatesCleared to further reduce the impact. + + // We set this to NONE because after a cursor move, we don't want the space + // state-related special processing to kick in. + mSpaceState = SPACE_STATE_NONE; + + if (((mWordComposer.isComposingWord()) || mVoiceProxy.isVoiceInputHighlighted()) && (selectionChanged || candidatesCleared)) { - mComposingStringBuilder.setLength(0); - mHasUncommittedTypedChars = false; - TextEntryState.reset(); + resetComposingState(true /* alsoResetLastComposedWord */); updateSuggestions(); final InputConnection ic = getCurrentInputConnection(); if (ic != null) { @@ -936,26 +892,25 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } mComposingStateManager.onFinishComposingText(); mVoiceProxy.setVoiceInputHighlighted(false); - } else if (!mHasUncommittedTypedChars) { - TextEntryState.reset(); + } else if (!mWordComposer.isComposingWord()) { + // TODO: is the following reset still needed, given that we are not composing + // a word? + resetComposingState(true /* alsoResetLastComposedWord */); 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 @@ -1011,7 +966,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } } - if (mApplicationSpecifiedCompletionOn) { + if (mInputAttributes.mApplicationSpecifiedCompletionOn) { mApplicationSpecifiedCompletions = applicationSpecifiedCompletions; if (applicationSpecifiedCompletions == null) { clearSuggestions(); @@ -1024,7 +979,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar .setHasMinimalSuggestion(false); // When in fullscreen mode, show completions generated by the application setSuggestions(builder.build()); - mBestWord = null; + // TODO: is this the right thing to do? What should we auto-correct to in + // this case? This says to keep whatever the user typed. + mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); setSuggestionStripShown(true); } } @@ -1032,8 +989,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private void setSuggestionStripShownInternal(boolean shown, boolean needsInputViewShown) { // TODO: Modify this if we support suggestions with hard keyboard if (onEvaluateInputViewShown() && mSuggestionsContainer != null) { + final LatinKeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); + final boolean inputViewShown = (keyboardView != null) ? keyboardView.isShown() : false; final boolean shouldShowSuggestions = shown - && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true); + && (needsInputViewShown ? inputViewShown : true); if (isFullscreenMode()) { mSuggestionsContainer.setVisibility( shouldShowSuggestions ? View.VISIBLE : View.GONE); @@ -1065,7 +1024,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final int extraHeight = extractHeight + backingHeight + suggestionsHeight; int touchY = extraHeight; // Need to set touchable region only if input view is being shown - if (mKeyboardSwitcher.isInputViewShown()) { + final LatinKeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); + if (keyboardView != null && keyboardView.isShown()) { if (mSuggestionsContainer.getVisibility() == View.VISIBLE) { touchY -= suggestionsHeight; } @@ -1085,8 +1045,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar @Override public boolean onEvaluateFullscreenMode() { - return super.onEvaluateFullscreenMode() - && mResources.getBoolean(R.bool.config_use_fullscreen_mode); + // Reread resource value here, because this method is called by framework anytime as needed. + final boolean isFullscreenModeAllowed = + mSettingsValues.isFullscreenModeAllowed(getResources()); + return super.onEvaluateFullscreenMode() && isFullscreenModeAllowed; } @Override @@ -1124,9 +1086,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar case KeyEvent.KEYCODE_DPAD_UP: case KeyEvent.KEYCODE_DPAD_LEFT: case KeyEvent.KEYCODE_DPAD_RIGHT: + final LatinKeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); + final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); // Enable shift key and DPAD to do selections - if (mKeyboardSwitcher.isInputViewShown() - && mKeyboardSwitcher.isShiftedOrShiftLocked()) { + if ((keyboardView != null && keyboardView.isShown()) + && (keyboard != null && keyboard.isShiftedOrShiftLocked())) { KeyEvent newEvent = new KeyEvent(event.getDownTime(), event.getEventTime(), event.getAction(), event.getKeyCode(), event.getRepeatCount(), event.getDeviceId(), event.getScanCode(), @@ -1141,16 +1105,21 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return super.onKeyUp(keyCode, event); } + private void resetComposingState(final boolean alsoResetLastComposedWord) { + mWordComposer.reset(); + if (alsoResetLastComposedWord) + mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; + } + public void commitTyped(final InputConnection ic) { - if (!mHasUncommittedTypedChars) return; - mHasUncommittedTypedChars = false; - if (mComposingStringBuilder.length() > 0) { + if (!mWordComposer.isComposingWord()) return; + final CharSequence typedWord = mWordComposer.getTypedWord(); + mLastComposedWord = mWordComposer.commitWord(LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD); + if (typedWord.length() > 0) { if (ic != null) { - ic.commitText(mComposingStringBuilder, 1); + ic.commitText(typedWord, 1); } - mCommittedLength = mComposingStringBuilder.length(); - TextEntryState.acceptedTyped(mComposingStringBuilder); - addToUserUnigramAndBigramDictionaries(mComposingStringBuilder, + addToUserUnigramAndBigramDictionaries(typedWord, UserUnigramDictionary.FREQUENCY_FOR_TYPED); } updateSuggestions(); @@ -1166,25 +1135,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)) @@ -1192,34 +1158,18 @@ 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(); - } - } - - // "ic" must not null - private 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); - if (lastOne != null && lastOne.length() == 1 - && lastOne.charAt(0) == Keyboard.CODE_PERIOD - && text.charAt(0) == Keyboard.CODE_PERIOD) { - ic.deleteSurroundingText(1, 0); + return true; } + return false; } - 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); @@ -1235,19 +1185,15 @@ 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() { if (isShowingOptionDialog()) return; if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) { showSubtypeSelectorAndSettings(); - } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm, false /* exclude aux subtypes */)) { + } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(false /* exclude aux subtypes */)) { showOptionsMenu(); } else { launchSettings(); @@ -1256,17 +1202,21 @@ 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) { if (isShowingOptionDialog()) return false; switch (requestCode) { case CODE_SHOW_INPUT_METHOD_PICKER: - if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm, true /* include aux subtypes */)) { + if (Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) { mImm.showInputMethodPicker(); return true; } return false; + case CODE_HAPTIC_AND_AUDIO_FEEDBACK: + hapticAndAudioFeedback(Keyboard.CODE_UNSPECIFIED); + return true; } return false; } @@ -1275,6 +1225,41 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return mOptionsDialog != null && mOptionsDialog.isShowing(); } + private void insertPunctuationFromSuggestionStrip(final int code) { + onCodeInput(code, new int[] { code }, + KeyboardActionListener.SUGGESTION_STRIP_COORDINATE, + KeyboardActionListener.SUGGESTION_STRIP_COORDINATE); + } + + private static int getEditorActionId(EditorInfo editorInfo) { + if (editorInfo == null) return 0; + return (editorInfo.actionLabel != null) + ? editorInfo.actionId + : (editorInfo.imeOptions & EditorInfo.IME_MASK_ACTION); + } + + private void performeEditorAction(int actionId) { + final InputConnection ic = getCurrentInputConnection(); + if (ic != null) { + ic.performEditorAction(actionId); + } + } + + private void sendKeyCodePoint(int code) { + // TODO: Remove this special handling of digit letters. + // For backward compatibility. See {@link InputMethodService#sendKeyChar(char)}. + if (code >= '0' && code <= '9') { + super.sendKeyChar((char)code); + return; + } + + final InputConnection ic = getCurrentInputConnection(); + if (ic != null) { + final String text = new String(new int[] { code }, 0, 1); + ic.commitText(text, text.length()); + } + } + // Implementation of {@link KeyboardActionListener}. @Override public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) { @@ -1284,55 +1269,39 @@ 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(); + } + + boolean didAutoCorrect = false; switch (primaryCode) { case Keyboard.CODE_DELETE: - handleBackspace(lastStateOfJustReplacedDoubleSpace); + mSpaceState = SPACE_STATE_NONE; + handleBackspace(spaceState); mDeleteCount++; mExpectingUpdateSelection = true; LatinImeLogger.logOnDelete(); break; case Keyboard.CODE_SHIFT: - // Shift key is handled in onPress() when device has distinct multi-touch panel. - 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(); - } - shouldStartKeyTypedTimer = false; - break; - case Keyboard.CODE_CANCEL: - if (!isShowingOptionDialog()) { - handleClose(); - } + // Shift and symbol key is handled in onPressKey() and onReleaseKey(). break; case Keyboard.CODE_SETTINGS: - if (!mHandler.isIgnoringSpecialKey()) { - onSettingsKeyPressed(); - } - shouldStartKeyTypedTimer = false; - 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); + onSettingsKeyPressed(); break; case Keyboard.CODE_SHORTCUT: - if (!mHandler.isIgnoringSpecialKey()) { - mSubtypeSwitcher.switchToShortcutIME(); - } - shouldStartKeyTypedTimer = false; + mSubtypeSwitcher.switchToShortcutIME(); + break; + case Keyboard.CODE_ACTION_ENTER: + performeEditorAction(getEditorActionId(getCurrentInputEditorInfo())); break; case Keyboard.CODE_TAB: handleTab(); @@ -1346,20 +1315,20 @@ 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); + didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState); } else { - handleCharacter(primaryCode, keyCodes, x, y); + handleCharacter(primaryCode, keyCodes, x, y, spaceState); } mExpectingUpdateSelection = true; break; } - switcher.onKey(primaryCode); + switcher.onCodeInput(primaryCode); // Reset after any single keystroke + if (!didAutoCorrect) + mLastComposedWord.deactivate(); mEnteredText = null; - if (shouldStartKeyTypedTimer) { - mHandler.startKeyTypedTimer(); - } } @Override @@ -1369,14 +1338,37 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (ic == null) return; ic.beginBatchEdit(); commitTyped(ic); - maybeRemovePreviousPeriod(ic, text); + text = specificTldProcessingOnTextInput(ic, text); + if (SPACE_STATE_PHANTOM == mSpaceState) { + sendKeyCodePoint(Keyboard.CODE_SPACE); + } ic.commitText(text, 1); ic.endBatchEdit(); mKeyboardSwitcher.updateShiftState(); - mKeyboardSwitcher.onKey(Keyboard.CODE_DUMMY); - mJustAddedMagicSpace = false; + mKeyboardSwitcher.onCodeInput(Keyboard.CODE_OUTPUT_TEXT); + mSpaceState = SPACE_STATE_NONE; mEnteredText = text; - mHandler.startKeyTypedTimer(); + resetComposingState(true /* alsoResetLastComposedWord */); + } + + // ic may not be null + private CharSequence specificTldProcessingOnTextInput(final InputConnection ic, + final CharSequence text) { + if (text.length() <= 1 || text.charAt(0) != Keyboard.CODE_PERIOD + || !Character.isLetter(text.charAt(1))) { + // Not a tld: do nothing. + return text; + } + // We have a TLD (or something that looks like this): make sure we don't add + // a space even if currently in phantom mode. + mSpaceState = SPACE_STATE_NONE; + final CharSequence lastOne = ic.getTextBeforeCursor(1, 0); + if (lastOne != null && lastOne.length() == 1 + && lastOne.charAt(0) == Keyboard.CODE_PERIOD) { + return text.subSequence(1, text.length()); + } else { + return text; + } } @Override @@ -1385,83 +1377,122 @@ 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(); if (ic == null) return; ic.beginBatchEdit(); + handleBackspaceWhileInBatchEdit(spaceState, ic); + ic.endBatchEdit(); + } + // "ic" may not be null. + private void handleBackspaceWhileInBatchEdit(final int spaceState, final InputConnection ic) { mVoiceProxy.handleBackspace(); - final boolean deleteChar = !mHasUncommittedTypedChars; - if (mHasUncommittedTypedChars) { - final int length = mComposingStringBuilder.length(); + // In many cases, we may have to put the keyboard in auto-shift state again. + mHandler.postUpdateShiftKeyState(); + + if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) { + // Cancel multi-character input: remove the text we just entered. + // This is triggered on backspace after a key that inputs multiple characters, + // like the smiley key or the .com key. + ic.deleteSurroundingText(mEnteredText.length(), 0); + // If we have mEnteredText, then we know that mHasUncommittedTypedChars == false. + // In addition we know that spaceState is false, and that we should not be + // reverting any autocorrect at this point. So we can safely return. + return; + } + + if (mWordComposer.isComposingWord()) { + final int length = mWordComposer.size(); if (length > 0) { - mComposingStringBuilder.delete(length - 1, length); mWordComposer.deleteLast(); - final CharSequence textWithUnderline = - mComposingStateManager.isAutoCorrectionIndicatorOn() - ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline( - this, mComposingStringBuilder) - : mComposingStringBuilder; - ic.setComposingText(textWithUnderline, 1); - if (mComposingStringBuilder.length() == 0) { - mHasUncommittedTypedChars = false; - } - if (1 == length) { - // 1 == length means we are about to erase the last character of the word, - // so we can show bigrams. + ic.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); + // If we have deleted the last remaining character of a word, then we are not + // isComposingWord() any more. + if (!mWordComposer.isComposingWord()) { + // Not composing word any more, so we can show bigrams. mHandler.postUpdateBigramPredictions(); } else { - // length > 1, so we still have letters to deduce a suggestion from. + // Still composing a word, so we still have letters to deduce a suggestion from. mHandler.postUpdateSuggestions(); } } else { ic.deleteSurroundingText(1, 0); } - } - mHandler.postUpdateShiftKeyState(); - - TextEntryState.backspace(); - if (TextEntryState.isUndoCommit()) { - revertLastWord(ic); - ic.endBatchEdit(); - return; - } - if (justReplacedDoubleSpace) { - if (revertDoubleSpace(ic)) { - ic.endBatchEdit(); + } else { + // We should be very careful about auto-correction cancellation and suggestion + // resuming here. The behavior needs to be different according to text field types, + // and it would be much clearer to test for them explicitly here rather than + // relying on implicit values like "whether the suggestion strip is displayed". + if (mLastComposedWord.canCancelAutoCorrect()) { + Utils.Stats.onAutoCorrectionCancellation(); + cancelAutoCorrect(ic); return; } - } - if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) { - ic.deleteSurroundingText(mEnteredText.length(), 0); - } else if (deleteChar) { + if (SPACE_STATE_DOUBLE == spaceState) { + if (revertDoubleSpaceWhileInBatchEdit(ic)) { + // 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)) { + // Likewise + return; + } + } + + // See the comment above: must be careful about resuming auto-suggestion. if (mSuggestionsView != null && mSuggestionsView.dismissAddToDictionaryHint()) { // Go back to the suggestion mode if the user canceled the // "Touch again to save". - // NOTE: In gerenal, we don't revert the word when backspacing + // NOTE: In general, we don't revert the word when backspacing // from a manual suggestion pick. We deliberately chose a // different behavior only in the case of picking the first // suggestion (typed word). It's intentional to have made this // inconsistent with backspacing after selecting other suggestions. - revertLastWord(ic); + restartSuggestionsOnManuallyPickedTypedWord(ic); } else { - sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); - if (mDeleteCount > DELETE_ACCELERATE_AT) { - sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); + // Here we must check whether there is a selection. If so we should remove the + // selected text, otherwise we should just delete the character before the cursor. + if (mLastSelectionStart != mLastSelectionEnd) { + final int lengthToDelete = mLastSelectionEnd - mLastSelectionStart; + ic.setSelection(mLastSelectionEnd, mLastSelectionEnd); + ic.deleteSurroundingText(lengthToDelete, 0); + } else { + if (NOT_A_CURSOR_POSITION == mLastSelectionEnd) { + // We don't know whether there is a selection or not. We just send a false + // hardware key event and let TextView sort it out for us. The problem + // here is, this is asynchronous with respect to the input connection + // batch edit, so it may flicker. But this only ever happens if backspace + // is pressed just after the IME is invoked, and then again only once. + // TODO: add an API call that gets the selection indices. This is available + // to the IME in the general case via onUpdateSelection anyway, and would + // allow us to remove this race condition. + sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); + } else { + ic.deleteSurroundingText(1, 0); + } + if (mDeleteCount > DELETE_ACCELERATE_AT) { + ic.deleteSurroundingText(1, 0); + } + } + if (isSuggestionsRequested()) { + restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(ic); } } } - ic.endBatchEdit(); } + // TODO: Implement next and previous actions using other key code than tab's code. private void handleTab() { final int imeOptions = getCurrentInputEditorInfo().imeOptions; if (!EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions) && !EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)) { + // TODO: This should be {@link #sendKeyCodePoint(int)}. sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB); return; } @@ -1470,89 +1501,108 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (ic == null) return; - // True if keyboard is in either chording shift or manual temporary upper case mode. - final boolean isManualTemporaryUpperCase = mKeyboardSwitcher.isManualTemporaryUpperCase(); - if (EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions) - && !isManualTemporaryUpperCase) { + final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); + // True if keyboard is in either shift chording or manual shifted state. + final boolean isManualShifted = (keyboard != null && keyboard.isManualShifted()); + if (EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions) && !isManualShifted) { EditorInfoCompatUtils.performEditorActionNext(ic); - } else if (EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions) - && isManualTemporaryUpperCase) { + } else if (EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions) && isManualShifted) { EditorInfoCompatUtils.performEditorActionPrevious(ic); } } - private void handleCharacter(int primaryCode, int[] keyCodes, int x, int y) { - mVoiceProxy.handleCharacter(); + // ic may be null + private boolean maybeStripSpaceWhileInBatchEdit(final InputConnection ic, final int code, + final int spaceState, final boolean isFromSuggestionStrip) { + if (Keyboard.CODE_ENTER == code && SPACE_STATE_SWAP_PUNCTUATION == spaceState) { + removeTrailingSpaceWhileInBatchEdit(ic); + return false; + } else if ((SPACE_STATE_WEAK == spaceState + || SPACE_STATE_SWAP_PUNCTUATION == spaceState) + && isFromSuggestionStrip) { + if (mSettingsValues.isMagicSpaceSwapper(code)) { + return true; + } else { + if (mSettingsValues.isMagicSpaceStripper(code)) { + removeTrailingSpaceWhileInBatchEdit(ic); + } + return false; + } + } else { + return false; + } + } - if (mJustAddedMagicSpace && mSettingsValues.isMagicSpaceStripper(primaryCode)) { - removeTrailingSpace(); + private void handleCharacter(final int primaryCode, final int[] keyCodes, final int x, + final int y, final int spaceState) { + mVoiceProxy.handleCharacter(); + final InputConnection ic = getCurrentInputConnection(); + if (null != ic) ic.beginBatchEdit(); + // TODO: if ic is null, does it make any sense to call this? + handleCharacterWhileInBatchEdit(primaryCode, keyCodes, x, y, spaceState, ic); + if (null != ic) ic.endBatchEdit(); + } + + // "ic" may be null without this crashing, but the behavior will be really strange + private void handleCharacterWhileInBatchEdit(final int primaryCode, final int[] keyCodes, + final int x, final int y, final int spaceState, final InputConnection ic) { + boolean isComposingWord = mWordComposer.isComposingWord(); + + if (SPACE_STATE_PHANTOM == spaceState && + !mSettingsValues.isSymbolExcludedFromWordSeparators(primaryCode)) { + if (isComposingWord) { + // Sanity check + throw new RuntimeException("Should not be composing here"); + } + sendKeyCodePoint(Keyboard.CODE_SPACE); } - int code = primaryCode; - if ((isAlphabet(code) || mSettingsValues.isSymbolExcludedFromWordSeparators(code)) + if ((isAlphabet(primaryCode) + || mSettingsValues.isSymbolExcludedFromWordSeparators(primaryCode)) && isSuggestionsRequested() && !isCursorTouchingWord()) { - if (!mHasUncommittedTypedChars) { - mHasUncommittedTypedChars = true; - mComposingStringBuilder.setLength(0); - mWordComposer.reset(); + if (!isComposingWord) { + // Reset entirely the composing state anyway, then start composing a new word unless + // the character is a single quote. The idea here is, single quote is not a + // separator and it should be treated as a normal character, except in the first + // position where it should not start composing a word. + isComposingWord = (Keyboard.CODE_SINGLE_QUOTE != primaryCode); + // Here we don't need to reset the last composed word. It will be reset + // when we commit this one, if we ever do; if on the other hand we backspace + // it entirely and resume suggestions on the previous word, we'd like to still + // have touch coordinates for it. + resetComposingState(false /* alsoResetLastComposedWord */); clearSuggestions(); mComposingStateManager.onFinishComposingText(); } } - final KeyboardSwitcher switcher = mKeyboardSwitcher; - if (switcher.isShiftedOrShiftLocked()) { - if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT - || keyCodes[0] > Character.MAX_CODE_POINT) { - return; - } - code = keyCodes[0]; - if (switcher.isAlphabetMode() && Character.isLowerCase(code)) { - // In some locales, such as Turkish, Character.toUpperCase() may return a wrong - // character because it doesn't take care of locale. - final String upperCaseString = new String(new int[] {code}, 0, 1) - .toUpperCase(mSubtypeSwitcher.getInputLocale()); - if (upperCaseString.codePointCount(0, upperCaseString.length()) == 1) { - code = upperCaseString.codePointAt(0); - } else { - // Some keys, such as [eszett], have upper case as multi-characters. - onTextInput(upperCaseString); - return; - } - } - } - if (mHasUncommittedTypedChars) { - mComposingStringBuilder.append((char) code); - mWordComposer.add(code, keyCodes, x, y); - final InputConnection ic = getCurrentInputConnection(); + if (isComposingWord) { + mWordComposer.add(primaryCode, keyCodes, x, y); if (ic != null) { // If it's the first letter, make note of auto-caps state if (mWordComposer.size() == 1) { mWordComposer.setAutoCapitalized(getCurrentAutoCapsState()); mComposingStateManager.onStartComposingText(); } - final CharSequence textWithUnderline = - mComposingStateManager.isAutoCorrectionIndicatorOn() - ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline( - this, mComposingStringBuilder) - : mComposingStringBuilder; - ic.setComposingText(textWithUnderline, 1); + ic.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); } mHandler.postUpdateSuggestions(); } else { - sendKeyChar((char)code); - } - if (mJustAddedMagicSpace && mSettingsValues.isMagicSpaceSwapper(primaryCode)) { - swapSwapperAndSpace(); - } else { - mJustAddedMagicSpace = false; - } + final boolean swapWeakSpace = maybeStripSpaceWhileInBatchEdit(ic, primaryCode, + spaceState, KeyboardActionListener.SUGGESTION_STRIP_COORDINATE == x); - switcher.updateShiftState(); - if (LatinIME.PERF_DEBUG) measureCps(); - TextEntryState.typedCharacter((char) code, mSettingsValues.isWordSeparator(code), x, y); + sendKeyCodePoint(primaryCode); + + if (swapWeakSpace) { + swapSwapperAndSpaceWhileInBatchEdit(ic); + mSpaceState = SPACE_STATE_WEAK; + } + } + Utils.Stats.onNonSeparator((char)primaryCode, x, y); } - private void handleSeparator(int primaryCode, int x, int y) { + // Returns true if we did an autocorrection, false otherwise. + private boolean handleSeparator(final int primaryCode, final int x, final int y, + final int spaceState) { mVoiceProxy.handleSeparator(); mComposingStateManager.onFinishComposingText(); @@ -1562,67 +1612,77 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mHandler.postUpdateSuggestions(); } - boolean pickedDefault = false; + boolean didAutoCorrect = false; // Handle separator final InputConnection ic = getCurrentInputConnection(); if (ic != null) { ic.beginBatchEdit(); } - if (mHasUncommittedTypedChars) { + if (mWordComposer.isComposingWord()) { // In certain languages where single quote is a separator, it's better // not to auto correct, but accept the typed word. For instance, // in Italian dov' should not be expanded to dove' because the elision // requires the last vowel to be removed. final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled - && !mInputTypeNoAutoCorrect; + && !mInputAttributes.mInputTypeNoAutoCorrect; if (shouldAutoCorrect && primaryCode != Keyboard.CODE_SINGLE_QUOTE) { - pickedDefault = pickDefaultSuggestion(primaryCode); + commitCurrentAutoCorrection(primaryCode, ic); + didAutoCorrect = true; } else { commitTyped(ic); } } - if (mJustAddedMagicSpace) { - if (mSettingsValues.isMagicSpaceSwapper(primaryCode)) { - sendKeyChar((char)primaryCode); - swapSwapperAndSpace(); - } else { - if (mSettingsValues.isMagicSpaceStripper(primaryCode)) removeTrailingSpace(); - sendKeyChar((char)primaryCode); - mJustAddedMagicSpace = false; - } - } else { - sendKeyChar((char)primaryCode); - } - - if (isSuggestionsRequested() && primaryCode == Keyboard.CODE_SPACE) { - maybeDoubleSpace(); - } + final boolean swapWeakSpace = maybeStripSpaceWhileInBatchEdit(ic, primaryCode, spaceState, + KeyboardActionListener.SUGGESTION_STRIP_COORDINATE == x); - TextEntryState.typedCharacter((char) primaryCode, true, x, y); + sendKeyCodePoint(primaryCode); - if (pickedDefault) { - CharSequence typedWord = mWordComposer.getTypedWord(); - TextEntryState.backToAcceptedDefault(typedWord); - if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) { - InputConnectionCompatUtils.commitCorrection( - ic, mLastSelectionEnd - typedWord.length(), typedWord, mBestWord); - } - } 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 (swapWeakSpace) { + swapSwapperAndSpaceWhileInBatchEdit(ic); + mSpaceState = SPACE_STATE_SWAP_PUNCTUATION; + } else if (SPACE_STATE_PHANTOM == spaceState) { + // If we are in phantom space state, and the user presses a separator, we want to + // stay in phantom space state so that the next keypress has a chance to add the + // space. For example, if I type "Good dat", pick "day" from the suggestion strip + // then insert a comma and go on to typing the next word, I want the space to be + // inserted automatically before the next word, the same way it is when I don't + // input the comma. + mSpaceState = SPACE_STATE_PHANTOM; + } + // Set punctuation right away. onUpdateSelection will fire but tests whether it is // already displayed or not, so it's okay. setPunctuationSuggestions(); } - mKeyboardSwitcher.updateShiftState(); + + Utils.Stats.onSeparator((char)primaryCode, x, y); + if (ic != null) { ic.endBatchEdit(); } + return didAutoCorrect; + } + + private CharSequence getTextWithUnderline(final CharSequence text) { + return mComposingStateManager.isAutoCorrectionIndicatorOn() + ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(this, text) + : text; } private void handleClose() { @@ -1635,7 +1695,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } public boolean isSuggestionsRequested() { - return mIsSettingsSuggestionStripOn + return mInputAttributes.mIsSettingsSuggestionStripOn && (mCorrectionMode > 0 || isShowingSuggestionsStrip()); } @@ -1653,11 +1713,11 @@ 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; - if (mApplicationSpecifiedCompletionOn) + if (mInputAttributes.mApplicationSpecifiedCompletionOn) return true; return isSuggestionsRequested(); } @@ -1698,18 +1758,20 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mComposingStateManager.isAutoCorrectionIndicatorOn(); final boolean newAutoCorrectionIndicator = Utils.willAutoCorrect(words); if (oldAutoCorrectionIndicator != newAutoCorrectionIndicator) { - if (LatinImeLogger.sDBG) { + mComposingStateManager.setAutoCorrectionIndicatorOn(newAutoCorrectionIndicator); + if (DEBUG) { Log.d(TAG, "Flip the indicator. " + oldAutoCorrectionIndicator + " -> " + newAutoCorrectionIndicator); + if (mComposingStateManager.isComposing() && newAutoCorrectionIndicator + != mComposingStateManager.isAutoCorrectionIndicatorOn()) { + throw new RuntimeException("Couldn't flip the indicator!"); + } } - final CharSequence textWithUnderline = newAutoCorrectionIndicator - ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline( - this, mComposingStringBuilder) - : mComposingStringBuilder; + final CharSequence textWithUnderline = + getTextWithUnderline(mWordComposer.getTypedWord()); if (!TextUtils.isEmpty(textWithUnderline)) { ic.setComposingText(textWithUnderline, 1); } - mComposingStateManager.setAutoCorrectionIndicatorOn(newAutoCorrectionIndicator); } } } @@ -1718,18 +1780,21 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Check if we have a suggestion engine attached. if ((mSuggest == null || !isSuggestionsRequested()) && !mVoiceProxy.isVoiceInputHighlighted()) { + if (mWordComposer.isComposingWord()) { + Log.w(TAG, "Called updateSuggestions but suggestions were not requested!"); + mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); + } return; } mHandler.cancelUpdateSuggestions(); mHandler.cancelUpdateBigramPredictions(); - if (!mHasUncommittedTypedChars) { + if (!mWordComposer.isComposingWord()) { setPunctuationSuggestions(); return; } - final WordComposer wordComposer = mWordComposer; // TODO: May need a better way of retrieving previous word final InputConnection ic = getCurrentInputConnection(); final CharSequence prevWord; @@ -1739,26 +1804,35 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar prevWord = EditingUtils.getPreviousWord(ic, mSettingsValues.mWordSeparators); } // getSuggestedWordBuilder handles gracefully a null value of prevWord - final SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder( - wordComposer, prevWord, mKeyboardSwitcher.getLatinKeyboard().getProximityInfo()); + final SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(mWordComposer, + prevWord, mKeyboardSwitcher.getKeyboard().getProximityInfo(), mCorrectionMode); - boolean autoCorrectionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasAutoCorrection(); - final CharSequence typedWord = wordComposer.getTypedWord(); + boolean autoCorrectionAvailable = !mInputAttributes.mInputTypeNoAutoCorrect + && mSuggest.hasAutoCorrection(); + final CharSequence typedWord = mWordComposer.getTypedWord(); // Here, we want to promote a whitelisted word if exists. // TODO: Change this scheme - a boolean is not enough. A whitelisted word may be "valid" // but still autocorrected from - in the case the whitelist only capitalizes the word. // 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 = mWordComposer.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(); + autoCorrectionAvailable &= !mWordComposer.isMostlyCaps(); // 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 @@ -1794,103 +1868,91 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar setSuggestions(suggestedWords); if (suggestedWords.size() > 0) { if (shouldBlockAutoCorrectionBySafetyNet) { - mBestWord = typedWord; + mWordComposer.setAutoCorrection(typedWord); } else if (suggestedWords.hasAutoCorrectionWord()) { - mBestWord = suggestedWords.getWord(1); + mWordComposer.setAutoCorrection(suggestedWords.getWord(1)); } else { - mBestWord = typedWord; + mWordComposer.setAutoCorrection(typedWord); } } else { - mBestWord = null; + // TODO: replace with mWordComposer.deleteAutoCorrection()? + mWordComposer.setAutoCorrection(null); } setSuggestionStripShown(isSuggestionsStripVisible()); } - private boolean pickDefaultSuggestion(int separatorCode) { + private void commitCurrentAutoCorrection(final int separatorCodePoint, + final InputConnection ic) { // Complete any pending suggestions query first if (mHandler.hasPendingUpdateSuggestions()) { mHandler.cancelUpdateSuggestions(); updateSuggestions(); } - if (mBestWord != null && mBestWord.length() > 0) { - TextEntryState.acceptedDefault(mWordComposer.getTypedWord(), mBestWord, separatorCode); + final CharSequence autoCorrection = mWordComposer.getAutoCorrectionOrNull(); + if (autoCorrection != null) { + final String typedWord = mWordComposer.getTypedWord(); + if (TextUtils.isEmpty(typedWord)) { + throw new RuntimeException("We have an auto-correction but the typed word " + + "is empty? Impossible! I must commit suicide."); + } + Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorCodePoint); mExpectingUpdateSelection = true; - commitBestWord(mBestWord); + commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD); // Add the word to the user unigram dictionary if it's not a known word - addToUserUnigramAndBigramDictionaries(mBestWord, + addToUserUnigramAndBigramDictionaries(autoCorrection, UserUnigramDictionary.FREQUENCY_FOR_TYPED); - return true; + if (!typedWord.equals(autoCorrection) && null != ic) { + // This will make the correction flash for a short while as a visual clue + // to the user that auto-correction happened. + InputConnectionCompatUtils.commitCorrection(ic, + mLastSelectionEnd - typedWord.length(), typedWord, autoCorrection); + } } - return false; } @Override - public void pickSuggestionManually(int index, CharSequence suggestion) { + public void pickSuggestionManually(final int index, final CharSequence suggestion) { mComposingStateManager.onFinishComposingText(); - SuggestedWords suggestions = mSuggestionsView.getSuggestions(); + final SuggestedWords suggestions = mSuggestionsView.getSuggestions(); mVoiceProxy.flushAndLogAllTextModificationCounters(index, suggestion, mSettingsValues.mWordSeparators); - final boolean recorrecting = TextEntryState.isRecorrecting(); - final InputConnection ic = getCurrentInputConnection(); - if (ic != null) { - ic.beginBatchEdit(); - } - if (mApplicationSpecifiedCompletionOn && mApplicationSpecifiedCompletions != null + if (mInputAttributes.mApplicationSpecifiedCompletionOn + && mApplicationSpecifiedCompletions != null && index >= 0 && index < mApplicationSpecifiedCompletions.length) { - if (ic != null) { - final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index]; - ic.commitCompletion(completionInfo); - } - mCommittedLength = suggestion.length(); if (mSuggestionsView != null) { mSuggestionsView.clear(); } mKeyboardSwitcher.updateShiftState(); + final InputConnection ic = getCurrentInputConnection(); if (ic != null) { + ic.beginBatchEdit(); + final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index]; + ic.commitCompletion(completionInfo); ic.endBatchEdit(); } return; } - // If this is a punctuation, apply it through the normal key press - if (suggestion.length() == 1 && (mSettingsValues.isWordSeparator(suggestion.charAt(0)) - || mSettingsValues.isSuggestedPunctuation(suggestion.charAt(0)))) { + // If this is a punctuation picked from the suggestion strip, pass it to onCodeInput + if (suggestion.length() == 1 && isShowingPunctuationList()) { // Word separators are suggested before the user inputs something. // So, LatinImeLogger logs "" as a user's input. 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 - // pressed space on purpose of displaying the suggestion strip punctuation. - final int rawPrimaryCode = suggestion.charAt(0); - // Maybe apply the "bidi mirrored" conversions for parentheses - final LatinKeyboard keyboard = mKeyboardSwitcher.getLatinKeyboard(); - 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; + // Rely on onCodeInput to do the complicated swapping/stripping logic consistently. + final int primaryCode = suggestion.charAt(0); onCodeInput(primaryCode, new int[] { primaryCode }, - KeyboardActionListener.NOT_A_TOUCH_COORDINATE, - KeyboardActionListener.NOT_A_TOUCH_COORDINATE); - mJustAddedMagicSpace = oldMagicSpace; - if (ic != null) { - ic.endBatchEdit(); - } + KeyboardActionListener.SUGGESTION_STRIP_COORDINATE, + KeyboardActionListener.SUGGESTION_STRIP_COORDINATE); return; } - if (!mHasUncommittedTypedChars) { - // If we are not composing a word, then it was a suggestion inferred from - // context - no user input. We should reset the word composer. - mWordComposer.reset(); - } + // We need to log before we commit, because the word composer will store away the user + // typed word. + LatinImeLogger.logOnManualSuggestion(mWordComposer.getTypedWord().toString(), + suggestion.toString(), index, suggestions.mWords); mExpectingUpdateSelection = true; - commitBestWord(suggestion); + commitChosenWord(suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK); // Add the word to the auto dictionary if it's not a known word if (index == 0) { addToUserUnigramAndBigramDictionaries(suggestion, @@ -1898,13 +1960,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } else { addToOnlyBigramDictionary(suggestion, 1); } - LatinImeLogger.logOnManualSuggestion(mComposingStringBuilder.toString(), - suggestion.toString(), index, suggestions.mWords); - TextEntryState.acceptedSuggestion(mComposingStringBuilder.toString(), suggestion); - // Follow it with a space - if (mInsertSpaceOnPickSuggestionManually && !recorrecting) { - sendMagicSpace(); - } + mSpaceState = SPACE_STATE_PHANTOM; + // TODO: is this necessary? + mKeyboardSwitcher.updateShiftState(); // We should show the "Touch again to save" hint if the user pressed the first entry // AND either: @@ -1922,13 +1980,8 @@ 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); - } + Utils.Stats.onSeparator((char)Keyboard.CODE_SPACE, 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,26 +1989,20 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Updating the predictions right away may be slow and feel unresponsive on slower // terminals. On the other hand if we just postUpdateBigramPredictions() it will // take a noticeable delay to update them which may feel uneasy. - } - if (showingAddToDictionaryHint) { - if (mIsUserDictionaryAvaliable) { - mSuggestionsView.showAddToDictionaryHint(suggestion); + } else { + if (mIsUserDictionaryAvailable) { + mSuggestionsView.showAddToDictionaryHint( + suggestion, mSettingsValues.mHintToSaveText); } else { mHandler.postUpdateSuggestions(); } } - if (ic != null) { - ic.endBatchEdit(); - } } /** * Commits the chosen word to the text field and saves it for later retrieval. */ - private void commitBestWord(CharSequence bestWord) { - final KeyboardSwitcher switcher = mKeyboardSwitcher; - if (!switcher.isKeyboardAvailable()) - return; + private void commitChosenWord(final CharSequence bestWord, final int commitType) { final InputConnection ic = getCurrentInputConnection(); if (ic != null) { mVoiceProxy.rememberReplacedWord(bestWord, mSettingsValues.mWordSeparators); @@ -1967,8 +2014,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar ic.commitText(bestWord, 1); } } - mHasUncommittedTypedChars = false; - mCommittedLength = bestWord.length(); + // TODO: figure out here if this is an auto-correct or if the best word is actually + // what user typed. Note: currently this is done much later in + // LastComposedWord#canCancelAutoCorrect by string equality of the remembered + // strings. + mLastComposedWord = mWordComposer.commitWord(commitType); } private static final WordComposer sEmptyWordComposer = new WordComposer(); @@ -1984,7 +2034,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final CharSequence prevWord = EditingUtils.getThisWord(getCurrentInputConnection(), mSettingsValues.mWordSeparators); SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(sEmptyWordComposer, - prevWord, mKeyboardSwitcher.getLatinKeyboard().getProximityInfo()); + prevWord, mKeyboardSwitcher.getKeyboard().getProximityInfo(), mCorrectionMode); if (builder.size() > 0) { // Explicitly supply an empty typed word (the no-second-arg version of @@ -2058,69 +2108,179 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar CharSequence toLeft = ic.getTextBeforeCursor(1, 0); CharSequence toRight = ic.getTextAfterCursor(1, 0); if (!TextUtils.isEmpty(toLeft) - && !mSettingsValues.isWordSeparator(toLeft.charAt(0)) - && !mSettingsValues.isSuggestedPunctuation(toLeft.charAt(0))) { + && !mSettingsValues.isWordSeparator(toLeft.charAt(0))) { return true; } if (!TextUtils.isEmpty(toRight) - && !mSettingsValues.isWordSeparator(toRight.charAt(0)) - && !mSettingsValues.isSuggestedPunctuation(toRight.charAt(0))) { + && !mSettingsValues.isWordSeparator(toRight.charAt(0))) { return true; } return false; } - // "ic" must not null - private boolean sameAsTextBeforeCursor(final InputConnection ic, CharSequence text) { - CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0); + // "ic" must not be null + private static boolean sameAsTextBeforeCursor(final InputConnection ic, + final CharSequence text) { + final CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0); return TextUtils.equals(text, beforeText); } - // "ic" must not null - private void revertLastWord(final InputConnection ic) { - if (mHasUncommittedTypedChars || mComposingStringBuilder.length() <= 0) { - sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); + // "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 "e-|" and "e|" are okay + CharSequence word = EditingUtils.getWordAtCursor(ic, mSettingsValues.mWordSeparators); + // We don't suggest on leading single quotes, so we have to remove them from the word if + // it starts with single quotes. + while (!TextUtils.isEmpty(word) && Keyboard.CODE_SINGLE_QUOTE == word.charAt(0)) { + word = word.subSequence(1, word.length()); + } + if (TextUtils.isEmpty(word)) return; + final char firstChar = word.charAt(0); // we just tested that word is not empty + if (word.length() == 1 && !Character.isLetter(firstChar)) return; + + // We only suggest on words that start with a letter or a symbol that is excluded from + // word separators (see #handleCharacterWhileInBatchEdit). + if (!(isAlphabet(firstChar) + || mSettingsValues.isSymbolExcludedFromWordSeparators(firstChar))) { 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.getKeyboard()); + mComposingStateManager.onStartComposingText(); + ic.deleteSurroundingText(word.length(), 0); + ic.setComposingText(word, 1); + mHandler.postUpdateSuggestions(); + } + + // "ic" must not be null + private void cancelAutoCorrect(final InputConnection ic) { + final String originallyTypedWord = mLastComposedWord.mTypedWord; + final CharSequence autoCorrectedTo = mLastComposedWord.mAutoCorrection; + final int cancelLength = autoCorrectedTo.length(); final CharSequence separator = ic.getTextBeforeCursor(1, 0); - ic.deleteSurroundingText(1, 0); - final CharSequence textToTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0); - ic.deleteSurroundingText(mCommittedLength, 0); - - // Re-insert "separator" only when the deleted character was word separator and the - // composing text wasn't equal to the auto-corrected text which can be found before - // the cursor. - if (!TextUtils.isEmpty(separator) - && mSettingsValues.isWordSeparator(separator.charAt(0)) - && !TextUtils.equals(mComposingStringBuilder, textToTheLeft)) { - ic.commitText(mComposingStringBuilder, 1); - TextEntryState.acceptedTyped(mComposingStringBuilder); - ic.commitText(separator, 1); - TextEntryState.typedCharacter(separator.charAt(0), true, - WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); - // Clear composing text - mComposingStringBuilder.setLength(0); - } else { - mHasUncommittedTypedChars = true; - ic.setComposingText(mComposingStringBuilder, 1); - TextEntryState.backspace(); + if (DEBUG) { + if (mWordComposer.isComposingWord()) { + throw new RuntimeException("cancelAutoCorrect, but we are composing a word"); + } + final String wordBeforeCursor = + ic.getTextBeforeCursor(cancelLength + 1, 0).subSequence(0, cancelLength) + .toString(); + if (!TextUtils.equals(autoCorrectedTo, wordBeforeCursor)) { + throw new RuntimeException("cancelAutoCorrect check failed: we thought we were " + + "reverting \"" + autoCorrectedTo + + "\", but before the cursor we found \"" + wordBeforeCursor + "\""); + } + if (TextUtils.equals(originallyTypedWord, wordBeforeCursor)) { + throw new RuntimeException("cancelAutoCorrect check failed: we wanted to cancel " + + "auto correction and revert to \"" + originallyTypedWord + + "\" but we found this very string before the cursor"); + } } + ic.deleteSurroundingText(cancelLength + 1, 0); + ic.commitText(originallyTypedWord, 1); + // Re-insert the separator + ic.commitText(separator, 1); + mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; + Utils.Stats.onSeparator(separator.charAt(0), WordComposer.NOT_A_COORDINATE, + WordComposer.NOT_A_COORDINATE); mHandler.cancelUpdateBigramPredictions(); mHandler.postUpdateSuggestions(); } - // "ic" must not null - private boolean revertDoubleSpace(final InputConnection ic) { + // "ic" must not be null + private void restartSuggestionsOnManuallyPickedTypedWord(final InputConnection ic) { + // Note: this relies on the last word still being held in the WordComposer, in + // the field for suggestion resuming. + // 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. + mWordComposer.resumeSuggestionOnLastComposedWord(mLastComposedWord); + // We resume suggestion, and then we want to set the composing text to the content + // of the word composer again. But since we just manually picked a word, there is + // no composing text at the moment, so we have to delete the word before we set a + // new composing text. + final int restartLength = mWordComposer.size(); + if (DEBUG) { + final String wordBeforeCursor = ic.getTextBeforeCursor(restartLength, 0).toString(); + if (!TextUtils.equals(mWordComposer.getTypedWord(), wordBeforeCursor)) { + throw new RuntimeException("restartSuggestionsOnManuallyPickedTypedWord " + + "check failed: we thought we were reverting \"" + + mWordComposer.getTypedWord() + + "\", but before the cursor we found \"" + + wordBeforeCursor + "\""); + } + } + ic.deleteSurroundingText(restartLength, 0); + mComposingStateManager.onStartComposingText(); + ic.setComposingText(mWordComposer.getTypedWord(), 1); + mHandler.cancelUpdateBigramPredictions(); + mHandler.postUpdateSuggestions(); + } + + // "ic" must not be null + private boolean revertDoubleSpaceWhileInBatchEdit(final InputConnection ic) { mHandler.cancelDoubleSpacesTimer(); // Here we test whether we indeed have a period and a space before us. This should not // be needed, but it's there just in case something went wrong. final CharSequence textBeforeCursor = ic.getTextBeforeCursor(2, 0); - if (!". ".equals(textBeforeCursor)) + if (!". ".equals(textBeforeCursor)) { + // Theoretically we should not be coming here if there isn't ". " before the + // cursor, but the application may be changing the text while we are typing, so + // anything goes. We should not crash. + Log.d(TAG, "Tried to revert double-space combo but we didn't find " + + "\". \" just before the cursor."); return false; - ic.beginBatchEdit(); + } ic.deleteSurroundingText(2, 0); ic.commitText(" ", 1); + 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 (TextUtils.isEmpty(textBeforeCursor) + || (Keyboard.CODE_SPACE != textBeforeCursor.charAt(1))) { + // We may only come here if the application is changing the text while we are typing. + // This is quite a broken case, but not logically impossible, so we shouldn't crash, + // but some debugging log may be in order. + Log.d(TAG, "Tried to revert a swap of punctuation but we didn't " + + "find a space just before the cursor."); + return false; + } + ic.beginBatchEdit(); + ic.deleteSurroundingText(2, 0); + ic.commitText(" " + textBeforeCursor.subSequence(0, 1), 1); ic.endBatchEdit(); return true; } @@ -2129,12 +2289,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return mSettingsValues.isWordSeparator(code); } - private void sendMagicSpace() { - sendKeyChar((char)Keyboard.CODE_SPACE); - mJustAddedMagicSpace = true; - mKeyboardSwitcher.updateShiftState(); - } - public boolean preferCapitalization() { return mWordComposer.isFirstCharCapitalized(); } @@ -2157,36 +2311,33 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar loadSettings(); } + public 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); - } - final boolean distinctMultiTouch = switcher.hasDistinctMultitouch(); - if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) { - switcher.onPressShift(withSliding); - } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { - switcher.onPressSymbol(); - } else { - switcher.onOtherKeyPressed(); - } + public void onPressKey(int primaryCode) { + mKeyboardSwitcher.onPressKey(primaryCode); } @Override - public void onRelease(int primaryCode, boolean withSliding) { - KeyboardSwitcher switcher = mKeyboardSwitcher; - // Reset any drag flags in the keyboard - final boolean distinctMultiTouch = switcher.hasDistinctMultitouch(); - if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) { - switcher.onReleaseShift(withSliding); - } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { - switcher.onReleaseSymbol(); + public void onReleaseKey(int primaryCode, boolean withSliding) { + mKeyboardSwitcher.onReleaseKey(primaryCode, withSliding); + + // If accessibility is on, ensure the user receives keyboard state updates. + if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { + switch (primaryCode) { + case Keyboard.CODE_SHIFT: + AccessibleKeyboardViewProxy.getInstance().notifyShiftState(); + break; + case Keyboard.CODE_SWITCH_ALPHA_SYMBOL: + AccessibleKeyboardViewProxy.getInstance().notifySymbolsState(); + break; + } } } - // receive ringer mode change and network state change. private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override @@ -2200,11 +2351,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } }; - // update keypress sound volume - private void updateSoundEffectVolume() { - mFxVolume = Utils.getCurrentKeypressSoundVolume(mPrefs, mResources); - } - // update flags for silent mode private void updateRingerMode() { if (mAudioManager == null) { @@ -2214,10 +2360,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mSilentModeOn = (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL); } - private void updateKeypressVibrationDuration() { - mKeypressVibrationDuration = Utils.getCurrentVibrationDuration(mPrefs, mResources); - } - private void playKeyClick(int primaryCode) { // if mAudioManager is null, we don't have the ringer state yet // mAudioManager will be set by updateRingerMode @@ -2242,7 +2384,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar sound = AudioManager.FX_KEYPRESS_STANDARD; break; } - mAudioManager.playSoundEffect(sound, mFxVolume); + mAudioManager.playSoundEffect(sound, mSettingsValues.mFxVolume); } } @@ -2250,7 +2392,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (!mSettingsValues.mVibrateOn) { return; } - if (mKeypressVibrationDuration < 0) { + if (mSettingsValues.mKeypressVibrationDuration < 0) { // Go ahead with the system default LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); if (inputView != null) { @@ -2259,12 +2401,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } } else if (mVibrator != null) { - mVibrator.vibrate(mKeypressVibrationDuration); + mVibrator.vibrate(mSettingsValues.mKeypressVibrationDuration); } } - public WordComposer getCurrentWord() { - return mWordComposer; + public boolean isAutoCapitalized() { + return mWordComposer.isAutoCapitalized(); } boolean isSoundOn() { @@ -2274,22 +2416,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private void updateCorrectionMode() { // TODO: cleanup messy flags final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled - && !mInputTypeNoAutoCorrect; - mCorrectionMode = (shouldAutoCorrect && mSettingsValues.mAutoCorrectEnabled) - ? Suggest.CORRECTION_FULL - : (shouldAutoCorrect ? Suggest.CORRECTION_BASIC : Suggest.CORRECTION_NONE); - mCorrectionMode = (mSettingsValues.mBigramSuggestionEnabled && shouldAutoCorrect - && mSettingsValues.mAutoCorrectEnabled) + && !mInputAttributes.mInputTypeNoAutoCorrect; + mCorrectionMode = shouldAutoCorrect ? Suggest.CORRECTION_FULL : Suggest.CORRECTION_NONE; + mCorrectionMode = (mSettingsValues.mBigramSuggestionEnabled && shouldAutoCorrect) ? Suggest.CORRECTION_FULL_BIGRAM : mCorrectionMode; - if (mSuggest != null) { - mSuggest.setCorrectionMode(mCorrectionMode); - } } - private void updateSuggestionVisibility(final SharedPreferences prefs, final Resources res) { - final String suggestionVisiblityStr = prefs.getString( - Settings.PREF_SHOW_SUGGESTIONS_SETTING, - res.getString(R.string.prefs_suggestion_visibility_default_value)); + private void updateSuggestionVisibility(final Resources res) { + final String suggestionVisiblityStr = mSettingsValues.mShowSuggestionsSetting; for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) { if (suggestionVisiblityStr.equals(res.getString(visibility))) { mSuggestionVisibility = visibility; @@ -2328,7 +2462,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar switch (position) { case 0: Intent intent = CompatUtils.getInputLanguageSelectionIntent( - mInputMethodId, Intent.FLAG_ACTIVITY_NEW_TASK + Utils.getInputMethodId(mImm, getPackageName()), + Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); @@ -2377,35 +2512,16 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final Printer p = new PrintWriterPrinter(fout); p.println("LatinIME state :"); - p.println(" Keyboard mode = " + mKeyboardSwitcher.getKeyboardMode()); - p.println(" mComposingStringBuilder=" + mComposingStringBuilder.toString()); - p.println(" mIsSuggestionsRequested=" + mIsSettingsSuggestionStripOn); + final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); + final int keyboardMode = keyboard != null ? keyboard.mId.mMode : -1; + p.println(" Keyboard mode = " + keyboardMode); + p.println(" mIsSuggestionsRequested=" + mInputAttributes.mIsSettingsSuggestionStripOn); p.println(" mCorrectionMode=" + mCorrectionMode); - p.println(" mHasUncommittedTypedChars=" + mHasUncommittedTypedChars); + p.println(" isComposingWord=" + mWordComposer.isComposingWord()); p.println(" mAutoCorrectEnabled=" + mSettingsValues.mAutoCorrectEnabled); - p.println(" mInsertSpaceOnPickSuggestionManually=" + mInsertSpaceOnPickSuggestionManually); - p.println(" mApplicationSpecifiedCompletionOn=" + mApplicationSpecifiedCompletionOn); - p.println(" TextEntryState.state=" + TextEntryState.getState()); p.println(" mSoundOn=" + mSettingsValues.mSoundOn); p.println(" mVibrateOn=" + mSettingsValues.mVibrateOn); p.println(" mKeyPreviewPopupOn=" + mSettingsValues.mKeyPreviewPopupOn); - } - - // Characters per second measurement - - private long mLastCpsTime; - private static final int CPS_BUFFER_SIZE = 16; - private long[] mCpsIntervals = new long[CPS_BUFFER_SIZE]; - private int mCpsIndex; - - private void measureCps() { - long now = System.currentTimeMillis(); - if (mLastCpsTime == 0) mLastCpsTime = now - 100; // Initial - mCpsIntervals[mCpsIndex] = now - mLastCpsTime; - mLastCpsTime = now; - mCpsIndex = (mCpsIndex + 1) % CPS_BUFFER_SIZE; - long total = 0; - for (int i = 0; i < CPS_BUFFER_SIZE; i++) total += mCpsIntervals[i]; - System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total)); + p.println(" mInputAttributes=" + mInputAttributes.toString()); } } diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java index ae8eb374b..e3dadf250 100644 --- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java +++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java @@ -16,11 +16,11 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.keyboard.Keyboard; -import com.android.inputmethod.latin.Dictionary.DataType; - import android.content.Context; import android.content.SharedPreferences; +import android.view.inputmethod.EditorInfo; + +import com.android.inputmethod.keyboard.Keyboard; import java.util.List; @@ -28,12 +28,13 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang public static boolean sDBG = false; public static boolean sVISUALDEBUG = false; + public static boolean sUsabilityStudy = false; @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { } - public static void init(Context context, SharedPreferences prefs) { + public static void init(LatinIME context, SharedPreferences prefs) { } public static void commit() { @@ -44,7 +45,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang public static void logOnManualSuggestion( String before, String after, int position, List<CharSequence> suggestions) { - } + } public static void logOnAutoCorrection(String before, String after, int separatorCode) { } @@ -67,10 +68,13 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang public static void logOnWarning(String warning) { } + public static void onStartInputView(EditorInfo editorInfo) { + } + public static void onStartSuggestion(CharSequence previousWords) { } - public static void onAddSuggestedWord(String word, int typeId, DataType dataType) { + public static void onAddSuggestedWord(String word, int typeId, int dataType) { } public static void onSetKeyboard(Keyboard kb) { @@ -78,4 +82,8 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang public static void onPrintAllUsabilityStudyLogs() { } + + public static boolean isResearcherPackage(Context context) { + return false; + } } diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 773efe709..d32310096 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -38,7 +38,6 @@ import android.text.TextUtils; import android.text.method.LinkMovementMethod; import android.util.Log; import android.view.View; -import android.view.inputmethod.EditorInfo; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; @@ -46,12 +45,10 @@ import android.widget.TextView; import com.android.inputmethod.compat.CompatUtils; import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; import com.android.inputmethod.compat.InputMethodServiceCompatWrapper; -import com.android.inputmethod.compat.InputTypeCompatUtils; import com.android.inputmethod.compat.VibratorCompatWrapper; import com.android.inputmethod.deprecated.VoiceProxy; import com.android.inputmethodcommon.InputMethodSettingsActivity; -import java.util.Arrays; import java.util.Locale; public class Settings extends InputMethodSettingsActivity @@ -61,255 +58,39 @@ public class Settings extends InputMethodSettingsActivity public static final boolean ENABLE_EXPERIMENTAL_SETTINGS = false; - public static final String PREF_GENERAL_SETTINGS_KEY = "general_settings"; + // In the same order as xml/prefs.xml + public static final String PREF_GENERAL_SETTINGS = "general_settings"; + public static final String PREF_SUBTYPES_SETTINGS = "subtype_settings"; + public static final String PREF_AUTO_CAP = "auto_cap"; public static final String PREF_VIBRATE_ON = "vibrate_on"; public static final String PREF_SOUND_ON = "sound_on"; - public static final String PREF_KEY_PREVIEW_POPUP_ON = "popup_on"; - public static final String PREF_AUTO_CAP = "auto_cap"; + public static final String PREF_POPUP_ON = "popup_on"; public static final String PREF_SHOW_SETTINGS_KEY = "show_settings_key"; - public static final String PREF_VOICE_SETTINGS_KEY = "voice_mode"; - public static final String PREF_INPUT_LANGUAGE = "input_language"; - public static final String PREF_SELECTED_LANGUAGES = "selected_languages"; - public static final String PREF_SUBTYPES = "subtype_settings"; - + public static final String PREF_VOICE_MODE = "voice_mode"; + public static final String PREF_CORRECTION_SETTINGS = "correction_settings"; public static final String PREF_CONFIGURE_DICTIONARIES_KEY = "configure_dictionaries_key"; - public static final String PREF_CORRECTION_SETTINGS_KEY = "correction_settings"; - public static final String PREF_SHOW_SUGGESTIONS_SETTING = "show_suggestions_setting"; public static final String PREF_AUTO_CORRECTION_THRESHOLD = "auto_correction_threshold"; - public static final String PREF_DEBUG_SETTINGS = "debug_settings"; - - public static final String PREF_BIGRAM_SUGGESTIONS = "bigram_suggestion"; - public static final String PREF_BIGRAM_PREDICTIONS = "bigram_prediction"; - - public static final String PREF_MISC_SETTINGS_KEY = "misc_settings"; - + public static final String PREF_SHOW_SUGGESTIONS_SETTING = "show_suggestions_setting"; + public static final String PREF_MISC_SETTINGS = "misc_settings"; + public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode"; + public static final String PREF_ADVANCED_SETTINGS = "pref_advanced_settings"; public static final String PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY = "pref_key_preview_popup_dismiss_delay"; - public static final String PREF_KEY_USE_CONTACTS_DICT = - "pref_key_use_contacts_dict"; - public static final String PREF_KEY_ENABLE_SPAN_INSERT = - "enable_span_insert"; - - public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode"; - - public static final String PREF_KEYPRESS_VIBRATION_DURATION_SETTINGS = + public static final String PREF_KEY_USE_CONTACTS_DICT = "pref_key_use_contacts_dict"; + public static final String PREF_BIGRAM_SUGGESTION = "bigram_suggestion"; + public static final String PREF_BIGRAM_PREDICTIONS = "bigram_prediction"; + public static final String PREF_KEY_ENABLE_SPAN_INSERT = "enable_span_insert"; + public static final String PREF_VIBRATION_DURATION_SETTINGS = "pref_vibration_duration_settings"; - public static final String PREF_KEYPRESS_SOUND_VOLUME = "pref_keypress_sound_volume"; - // Dialog ids - private static final int VOICE_INPUT_CONFIRM_DIALOG = 0; - - public static class Values { - // From resources: - public final int mDelayUpdateOldSuggestions; - public final String mWordSeparators; - public final String mMagicSpaceStrippers; - public final String mMagicSpaceSwappers; - public final String mSuggestPuncs; - public final SuggestedWords mSuggestPuncList; - private final String mSymbolsExcludedFromWordSeparators; - - // From preferences: - public final boolean mSoundOn; // Sound setting private to Latin IME (see mSilentModeOn) - public final boolean mVibrateOn; - public final boolean mKeyPreviewPopupOn; - public final int mKeyPreviewPopupDismissDelay; - public final boolean mAutoCap; - public final boolean mAutoCorrectEnabled; - public final double mAutoCorrectionThreshold; - // Suggestion: use bigrams to adjust scores of suggestions obtained from unigram dictionary - public final boolean mBigramSuggestionEnabled; - // Prediction: use bigrams to predict the next word when there is no input for it yet - public final boolean mBigramPredictionEnabled; - public final boolean mUseContactsDict; - public final boolean mEnableSuggestionSpanInsertion; - - private final boolean mShowSettingsKey; - private final boolean mVoiceKeyEnabled; - private final boolean mVoiceKeyOnMain; - - public Values(final SharedPreferences prefs, final Context context, - final String localeStr) { - final Resources res = context.getResources(); - final Locale savedLocale; - if (null != localeStr) { - final Locale keyboardLocale = LocaleUtils.constructLocaleFromString(localeStr); - savedLocale = LocaleUtils.setSystemLocale(res, keyboardLocale); - } else { - savedLocale = null; - } - - // Get the resources - mDelayUpdateOldSuggestions = res.getInteger( - R.integer.config_delay_update_old_suggestions); - mMagicSpaceStrippers = res.getString(R.string.magic_space_stripping_symbols); - mMagicSpaceSwappers = res.getString(R.string.magic_space_swapping_symbols); - String wordSeparators = mMagicSpaceStrippers + mMagicSpaceSwappers - + res.getString(R.string.magic_space_promoting_symbols); - final String symbolsExcludedFromWordSeparators = - res.getString(R.string.symbols_excluded_from_word_separators); - for (int i = symbolsExcludedFromWordSeparators.length() - 1; i >= 0; --i) { - wordSeparators = wordSeparators.replace( - symbolsExcludedFromWordSeparators.substring(i, i + 1), ""); - } - mSymbolsExcludedFromWordSeparators = symbolsExcludedFromWordSeparators; - mWordSeparators = wordSeparators; - 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); - - // Get the settings preferences - final boolean hasVibrator = VibratorCompatWrapper.getInstance(context).hasVibrator(); - mVibrateOn = hasVibrator && prefs.getBoolean(Settings.PREF_VIBRATE_ON, - res.getBoolean(R.bool.config_default_vibration_enabled)); - mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON, - res.getBoolean(R.bool.config_default_sound_enabled)); - mKeyPreviewPopupOn = isKeyPreviewPopupEnabled(prefs, res); - mKeyPreviewPopupDismissDelay = getKeyPreviewPopupDismissDelay(prefs, res); - mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true); - mAutoCorrectEnabled = isAutoCorrectEnabled(prefs, res); - mBigramSuggestionEnabled = mAutoCorrectEnabled - && isBigramSuggestionEnabled(prefs, res, mAutoCorrectEnabled); - mBigramPredictionEnabled = mBigramSuggestionEnabled - && isBigramPredictionEnabled(prefs, res); - mAutoCorrectionThreshold = getAutoCorrectionThreshold(prefs, res); - mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true); - mEnableSuggestionSpanInsertion = - prefs.getBoolean(Settings.PREF_KEY_ENABLE_SPAN_INSERT, true); - final boolean defaultShowSettingsKey = res.getBoolean( - R.bool.config_default_show_settings_key); - mShowSettingsKey = isShowSettingsKeyOption(res) - ? prefs.getBoolean(Settings.PREF_SHOW_SETTINGS_KEY, defaultShowSettingsKey) - : defaultShowSettingsKey; - final String voiceModeMain = res.getString(R.string.voice_mode_main); - final String voiceModeOff = res.getString(R.string.voice_mode_off); - final String voiceMode = prefs.getString(PREF_VOICE_SETTINGS_KEY, voiceModeMain); - mVoiceKeyEnabled = voiceMode != null && !voiceMode.equals(voiceModeOff); - mVoiceKeyOnMain = voiceMode != null && voiceMode.equals(voiceModeMain); - - LocaleUtils.setSystemLocale(res, savedLocale); - } - public boolean isSuggestedPunctuation(int code) { - return mSuggestPuncs.contains(String.valueOf((char)code)); - } - - public boolean isWordSeparator(int code) { - return mWordSeparators.contains(String.valueOf((char)code)); - } - - public boolean isSymbolExcludedFromWordSeparators(int code) { - return mSymbolsExcludedFromWordSeparators.contains(String.valueOf((char)code)); - } - - public boolean isMagicSpaceStripper(int code) { - return mMagicSpaceStrippers.contains(String.valueOf((char)code)); - } - - public boolean isMagicSpaceSwapper(int code) { - return mMagicSpaceSwappers.contains(String.valueOf((char)code)); - } - - private static boolean isAutoCorrectEnabled(SharedPreferences sp, Resources resources) { - final String currentAutoCorrectionSetting = sp.getString( - Settings.PREF_AUTO_CORRECTION_THRESHOLD, - resources.getString(R.string.auto_correction_threshold_mode_index_modest)); - final String autoCorrectionOff = resources.getString( - R.string.auto_correction_threshold_mode_index_off); - return !currentAutoCorrectionSetting.equals(autoCorrectionOff); - } - - // Public to access from KeyboardSwitcher. Should it have access to some - // process-global instance instead? - public static boolean isKeyPreviewPopupEnabled(SharedPreferences sp, Resources resources) { - final boolean showPopupOption = resources.getBoolean( - R.bool.config_enable_show_popup_on_keypress_option); - if (!showPopupOption) return resources.getBoolean(R.bool.config_default_popup_preview); - return sp.getBoolean(Settings.PREF_KEY_PREVIEW_POPUP_ON, - resources.getBoolean(R.bool.config_default_popup_preview)); - } - - // Likewise - public static int getKeyPreviewPopupDismissDelay(SharedPreferences sp, - Resources resources) { - return Integer.parseInt(sp.getString(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, - Integer.toString(resources.getInteger(R.integer.config_delay_after_preview)))); - } - - private static boolean isBigramSuggestionEnabled(SharedPreferences sp, Resources resources, - boolean autoCorrectEnabled) { - final boolean showBigramSuggestionsOption = resources.getBoolean( - R.bool.config_enable_bigram_suggestions_option); - if (!showBigramSuggestionsOption) { - return autoCorrectEnabled; - } - return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, resources.getBoolean( - R.bool.config_default_bigram_suggestions)); - } - - private static boolean isBigramPredictionEnabled(SharedPreferences sp, - Resources resources) { - return sp.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, resources.getBoolean( - R.bool.config_default_bigram_prediction)); - } - - private static double getAutoCorrectionThreshold(SharedPreferences sp, - Resources resources) { - final String currentAutoCorrectionSetting = sp.getString( - Settings.PREF_AUTO_CORRECTION_THRESHOLD, - resources.getString(R.string.auto_correction_threshold_mode_index_modest)); - final String[] autoCorrectionThresholdValues = resources.getStringArray( - R.array.auto_correction_threshold_values); - // When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off. - double autoCorrectionThreshold = Double.MAX_VALUE; - try { - final int arrayIndex = Integer.valueOf(currentAutoCorrectionSetting); - if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) { - autoCorrectionThreshold = Double.parseDouble( - autoCorrectionThresholdValues[arrayIndex]); - } - } catch (NumberFormatException e) { - // Whenever the threshold settings are correct, never come here. - autoCorrectionThreshold = Double.MAX_VALUE; - Log.w(TAG, "Cannot load auto correction threshold setting." - + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting - + ", autoCorrectionThresholdValues: " - + Arrays.toString(autoCorrectionThresholdValues)); - } - return autoCorrectionThreshold; - } - - private static SuggestedWords createSuggestPuncList(final String puncs) { - SuggestedWords.Builder builder = new SuggestedWords.Builder(); - if (puncs != null) { - for (int i = 0; i < puncs.length(); i++) { - builder.addWord(puncs.subSequence(i, i + 1)); - } - } - return builder.setIsPunctuationSuggestions().build(); - } - - public static boolean isShowSettingsKeyOption(final Resources resources) { - return resources.getBoolean(R.bool.config_enable_show_settings_key_option); - - } - - public boolean isSettingsKeyEnabled() { - return mShowSettingsKey; - } - - public boolean isVoiceKeyEnabled(EditorInfo attribute) { - final boolean shortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled(); - final int inputType = (attribute != null) ? attribute.inputType : 0; - return shortcutImeEnabled && mVoiceKeyEnabled - && !InputTypeCompatUtils.isPasswordInputType(inputType); - } + public static final String PREF_INPUT_LANGUAGE = "input_language"; + public static final String PREF_SELECTED_LANGUAGES = "selected_languages"; + public static final String PREF_DEBUG_SETTINGS = "debug_settings"; - public boolean isVoiceKeyOnMain() { - return mVoiceKeyOnMain; - } - } + // Dialog ids + private static final int VOICE_INPUT_CONFIRM_DIALOG = 0; private PreferenceScreen mInputLanguageSelection; private PreferenceScreen mKeypressVibrationDurationSettingsPref; @@ -363,9 +144,9 @@ public class Settings extends InputMethodSettingsActivity final Context context = getActivityInternal(); addPreferencesFromResource(R.xml.prefs); - mInputLanguageSelection = (PreferenceScreen) findPreference(PREF_SUBTYPES); + mInputLanguageSelection = (PreferenceScreen) findPreference(PREF_SUBTYPES_SETTINGS); mInputLanguageSelection.setOnPreferenceClickListener(this); - mVoicePreference = (ListPreference) findPreference(PREF_VOICE_SETTINGS_KEY); + mVoicePreference = (ListPreference) findPreference(PREF_VOICE_MODE); mShowSettingsKeyPreference = (CheckBoxPreference) findPreference(PREF_SHOW_SETTINGS_KEY); mShowCorrectionSuggestionsPreference = (ListPreference) findPreference(PREF_SHOW_SUGGESTIONS_SETTING); @@ -373,12 +154,12 @@ public class Settings extends InputMethodSettingsActivity prefs.registerOnSharedPreferenceChangeListener(this); mVoiceModeOff = getString(R.string.voice_mode_off); - mVoiceOn = !(prefs.getString(PREF_VOICE_SETTINGS_KEY, mVoiceModeOff) + mVoiceOn = !(prefs.getString(PREF_VOICE_MODE, mVoiceModeOff) .equals(mVoiceModeOff)); mAutoCorrectionThresholdPreference = (ListPreference) findPreference(PREF_AUTO_CORRECTION_THRESHOLD); - mBigramSuggestion = (CheckBoxPreference) findPreference(PREF_BIGRAM_SUGGESTIONS); + mBigramSuggestion = (CheckBoxPreference) findPreference(PREF_BIGRAM_SUGGESTION); mBigramPrediction = (CheckBoxPreference) findPreference(PREF_BIGRAM_PREDICTIONS); mDebugSettingsPreference = findPreference(PREF_DEBUG_SETTINGS); if (mDebugSettingsPreference != null) { @@ -391,13 +172,13 @@ public class Settings extends InputMethodSettingsActivity ensureConsistencyOfAutoCorrectionSettings(); final PreferenceGroup generalSettings = - (PreferenceGroup) findPreference(PREF_GENERAL_SETTINGS_KEY); + (PreferenceGroup) findPreference(PREF_GENERAL_SETTINGS); final PreferenceGroup textCorrectionGroup = - (PreferenceGroup) findPreference(PREF_CORRECTION_SETTINGS_KEY); + (PreferenceGroup) findPreference(PREF_CORRECTION_SETTINGS); final PreferenceGroup miscSettings = - (PreferenceGroup) findPreference(PREF_MISC_SETTINGS_KEY); + (PreferenceGroup) findPreference(PREF_MISC_SETTINGS); - if (!Values.isShowSettingsKeyOption(res)) { + if (!SettingsValues.isShowSettingsKeyOptionEnabled(res)) { generalSettings.removePreference(mShowSettingsKeyPreference); } @@ -412,13 +193,13 @@ public class Settings extends InputMethodSettingsActivity } if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) { - generalSettings.removePreference(findPreference(PREF_SUBTYPES)); + generalSettings.removePreference(findPreference(PREF_SUBTYPES_SETTINGS)); } final boolean showPopupOption = res.getBoolean( R.bool.config_enable_show_popup_on_keypress_option); if (!showPopupOption) { - generalSettings.removePreference(findPreference(PREF_KEY_PREVIEW_POPUP_ON)); + generalSettings.removePreference(findPreference(PREF_POPUP_ON)); } final boolean showBigramSuggestionsOption = res.getBoolean( @@ -437,14 +218,15 @@ public class Settings extends InputMethodSettingsActivity res.getString(R.string.key_preview_popup_dismiss_default_delay), }; final String popupDismissDelayDefaultValue = Integer.toString(res.getInteger( - R.integer.config_delay_after_preview)); + R.integer.config_key_preview_linger_timeout)); mKeyPreviewPopupDismissDelay.setEntries(entries); mKeyPreviewPopupDismissDelay.setEntryValues( new String[] { "0", popupDismissDelayDefaultValue }); if (null == mKeyPreviewPopupDismissDelay.getValue()) { mKeyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue); } - mKeyPreviewPopupDismissDelay.setEnabled(Values.isKeyPreviewPopupEnabled(prefs, res)); + mKeyPreviewPopupDismissDelay.setEnabled( + SettingsValues.isKeyPreviewPopupEnabled(prefs, res)); final PreferenceScreen dictionaryLink = (PreferenceScreen) findPreference(PREF_CONFIGURE_DICTIONARIES_KEY); @@ -455,17 +237,26 @@ public class Settings extends InputMethodSettingsActivity textCorrectionGroup.removePreference(dictionaryLink); } - final boolean showUsabilityModeStudyOption = res.getBoolean( - R.bool.config_enable_usability_study_mode_option); - if (!showUsabilityModeStudyOption || !ENABLE_EXPERIMENTAL_SETTINGS) { - final Preference pref = findPreference(PREF_USABILITY_STUDY_MODE); - if (pref != null) { - miscSettings.removePreference(pref); + final boolean isResearcherPackage = LatinImeLogger.isResearcherPackage(this); + final boolean showUsabilityStudyModeOption = + res.getBoolean(R.bool.config_enable_usability_study_mode_option) + || isResearcherPackage || ENABLE_EXPERIMENTAL_SETTINGS; + final Preference usabilityStudyPref = findPreference(PREF_USABILITY_STUDY_MODE); + if (!showUsabilityStudyModeOption) { + if (usabilityStudyPref != null) { + miscSettings.removePreference(usabilityStudyPref); + } + } + if (isResearcherPackage) { + if (usabilityStudyPref instanceof CheckBoxPreference) { + CheckBoxPreference checkbox = (CheckBoxPreference)usabilityStudyPref; + checkbox.setChecked(prefs.getBoolean(PREF_USABILITY_STUDY_MODE, true)); + checkbox.setSummary(R.string.settings_warning_researcher_mode); } } mKeypressVibrationDurationSettingsPref = - (PreferenceScreen) findPreference(PREF_KEYPRESS_VIBRATION_DURATION_SETTINGS); + (PreferenceScreen) findPreference(PREF_VIBRATION_DURATION_SETTINGS); if (mKeypressVibrationDurationSettingsPref != null) { mKeypressVibrationDurationSettingsPref.setOnPreferenceClickListener( new OnPreferenceClickListener() { @@ -521,20 +312,20 @@ public class Settings extends InputMethodSettingsActivity public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { (new BackupManager(getActivityInternal())).dataChanged(); // If turning on voice input, show dialog - if (key.equals(PREF_VOICE_SETTINGS_KEY) && !mVoiceOn) { - if (!prefs.getString(PREF_VOICE_SETTINGS_KEY, mVoiceModeOff) + if (key.equals(PREF_VOICE_MODE) && !mVoiceOn) { + if (!prefs.getString(PREF_VOICE_MODE, mVoiceModeOff) .equals(mVoiceModeOff)) { showVoiceConfirmation(); } - } else if (key.equals(PREF_KEY_PREVIEW_POPUP_ON)) { + } else if (key.equals(PREF_POPUP_ON)) { final ListPreference popupDismissDelay = (ListPreference)findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY); if (null != popupDismissDelay) { - popupDismissDelay.setEnabled(prefs.getBoolean(PREF_KEY_PREVIEW_POPUP_ON, true)); + popupDismissDelay.setEnabled(prefs.getBoolean(PREF_POPUP_ON, true)); } } ensureConsistencyOfAutoCorrectionSettings(); - mVoiceOn = !(prefs.getString(PREF_VOICE_SETTINGS_KEY, mVoiceModeOff) + mVoiceOn = !(prefs.getString(PREF_VOICE_MODE, mVoiceModeOff) .equals(mVoiceModeOff)); updateVoiceModeSummary(); updateShowCorrectionSuggestionsSummary(); @@ -660,7 +451,7 @@ public class Settings extends InputMethodSettingsActivity SharedPreferences sp, Resources res) { if (mKeypressVibrationDurationSettingsPref != null) { mKeypressVibrationDurationSettingsPref.setSummary( - Utils.getCurrentVibrationDuration(sp, res) + SettingsValues.getCurrentVibrationDuration(sp, res) + res.getString(R.string.settings_ms)); } } @@ -676,7 +467,7 @@ public class Settings extends InputMethodSettingsActivity public void onClick(DialogInterface dialog, int whichButton) { final int ms = Integer.valueOf( mKeypressVibrationDurationSettingsTextView.getText().toString()); - sp.edit().putInt(Settings.PREF_KEYPRESS_VIBRATION_DURATION_SETTINGS, ms).apply(); + sp.edit().putInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, ms).apply(); updateKeypressVibrationDurationSettingsSummary(sp, res); } }); @@ -688,7 +479,7 @@ public class Settings extends InputMethodSettingsActivity }); final View v = context.getLayoutInflater().inflate( R.layout.vibration_settings_dialog, null); - final int currentMs = Utils.getCurrentVibrationDuration( + final int currentMs = SettingsValues.getCurrentVibrationDuration( getPreferenceManager().getSharedPreferences(), getResources()); mKeypressVibrationDurationSettingsTextView = (TextView)v.findViewById(R.id.vibration_value); final SeekBar sb = (SeekBar)v.findViewById(R.id.vibration_settings); @@ -717,8 +508,8 @@ public class Settings extends InputMethodSettingsActivity private void updateKeypressSoundVolumeSummary(SharedPreferences sp, Resources res) { if (mKeypressSoundVolumeSettingsPref != null) { - mKeypressSoundVolumeSettingsPref.setSummary( - String.valueOf((int)(Utils.getCurrentKeypressSoundVolume(sp, res) * 100))); + mKeypressSoundVolumeSettingsPref.setSummary(String.valueOf( + (int)(SettingsValues.getCurrentKeypressSoundVolume(sp, res) * 100))); } } @@ -747,8 +538,8 @@ public class Settings extends InputMethodSettingsActivity }); final View v = context.getLayoutInflater().inflate( R.layout.sound_effect_volume_dialog, null); - final int currentVolumeInt = (int)(Utils.getCurrentKeypressSoundVolume( - getPreferenceManager().getSharedPreferences(), getResources()) * 100); + final int currentVolumeInt = + (int)(SettingsValues.getCurrentKeypressSoundVolume(sp, res) * 100); mKeypressSoundVolumeSettingsTextView = (TextView)v.findViewById(R.id.sound_effect_volume_value); final SeekBar sb = (SeekBar)v.findViewById(R.id.sound_effect_volume_bar); @@ -774,4 +565,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/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java new file mode 100644 index 000000000..6b652313c --- /dev/null +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.os.Build; +import android.util.Log; +import android.view.inputmethod.EditorInfo; + +import com.android.inputmethod.compat.InputTypeCompatUtils; +import com.android.inputmethod.compat.VibratorCompatWrapper; +import com.android.inputmethod.keyboard.internal.KeySpecParser; + +import java.util.Arrays; +import java.util.Locale; + +public class SettingsValues { + private static final String TAG = SettingsValues.class.getSimpleName(); + + // From resources: + public final int mDelayUpdateOldSuggestions; + public final String mMagicSpaceStrippers; + public final String mMagicSpaceSwappers; + private final String mSuggestPuncs; + public final SuggestedWords mSuggestPuncList; + public final SuggestedWords mSuggestPuncOutputTextList; + private final String mSymbolsExcludedFromWordSeparators; + public final String mWordSeparators; + public final CharSequence mHintToSaveText; + + // From preferences, in the same order as xml/prefs.xml: + public final boolean mAutoCap; + public final boolean mVibrateOn; + public final boolean mSoundOn; + public final boolean mKeyPreviewPopupOn; + private final boolean mShowSettingsKey; + private final String mVoiceMode; + private final String mAutoCorrectionThresholdRawValue; + public final String mShowSuggestionsSetting; + @SuppressWarnings("unused") // TODO: Use this + private final boolean mUsabilityStudyMode; + @SuppressWarnings("unused") // TODO: Use this + private final String mKeyPreviewPopupDismissDelayRawValue; + public final boolean mUseContactsDict; + // Suggestion: use bigrams to adjust scores of suggestions obtained from unigram dictionary + public final boolean mBigramSuggestionEnabled; + // Prediction: use bigrams to predict the next word when there is no input for it yet + public final boolean mBigramPredictionEnabled; + public final boolean mEnableSuggestionSpanInsertion; + @SuppressWarnings("unused") // TODO: Use this + private final int mVibrationDurationSettingsRawValue; + @SuppressWarnings("unused") // TODO: Use this + private final float mKeypressSoundVolumeRawValue; + + // Deduced settings + public final int mKeypressVibrationDuration; + public final float mFxVolume; + public final int mKeyPreviewPopupDismissDelay; + public final boolean mAutoCorrectEnabled; + public final double mAutoCorrectionThreshold; + private final boolean mVoiceKeyEnabled; + private final boolean mVoiceKeyOnMain; + + public SettingsValues(final SharedPreferences prefs, final Context context, + final String localeStr) { + final Resources res = context.getResources(); + final Locale savedLocale; + if (null != localeStr) { + final Locale keyboardLocale = LocaleUtils.constructLocaleFromString(localeStr); + savedLocale = LocaleUtils.setSystemLocale(res, keyboardLocale); + } else { + savedLocale = null; + } + + // Get the resources + mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions); + mMagicSpaceStrippers = res.getString(R.string.magic_space_stripping_symbols); + mMagicSpaceSwappers = res.getString(R.string.magic_space_swapping_symbols); + if (LatinImeLogger.sDBG) { + final int length = mMagicSpaceStrippers.length(); + for (int i = 0; i < length; i = mMagicSpaceStrippers.offsetByCodePoints(i, 1)) { + if (isMagicSpaceSwapper(mMagicSpaceStrippers.codePointAt(i))) { + throw new RuntimeException("Char code " + mMagicSpaceStrippers.codePointAt(i) + + " is both a magic space swapper and stripper."); + } + } + } + final String[] suggestPuncsSpec = KeySpecParser.parseCsvString( + res.getString(R.string.suggested_punctuations), res, R.string.english_ime_name); + mSuggestPuncs = createSuggestPuncs(suggestPuncsSpec); + mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec); + mSuggestPuncOutputTextList = createSuggestPuncOutputTextList(suggestPuncsSpec); + mSymbolsExcludedFromWordSeparators = + res.getString(R.string.symbols_excluded_from_word_separators); + mWordSeparators = createWordSeparators(mMagicSpaceStrippers, mMagicSpaceSwappers, + mSymbolsExcludedFromWordSeparators, res); + mHintToSaveText = context.getText(R.string.hint_add_to_dictionary); + + // Get the settings preferences + mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true); + mVibrateOn = isVibrateOn(context, prefs, res); + mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON, + res.getBoolean(R.bool.config_default_sound_enabled)); + mKeyPreviewPopupOn = isKeyPreviewPopupEnabled(prefs, res); + mShowSettingsKey = isSettingsKeyShown(prefs, res); + final String voiceModeMain = res.getString(R.string.voice_mode_main); + final String voiceModeOff = res.getString(R.string.voice_mode_off); + mVoiceMode = prefs.getString(Settings.PREF_VOICE_MODE, voiceModeMain); + mAutoCorrectionThresholdRawValue = prefs.getString(Settings.PREF_AUTO_CORRECTION_THRESHOLD, + res.getString(R.string.auto_correction_threshold_mode_index_modest)); + mShowSuggestionsSetting = prefs.getString(Settings.PREF_SHOW_SUGGESTIONS_SETTING, + res.getString(R.string.prefs_suggestion_visibility_default_value)); + mUsabilityStudyMode = getUsabilityStudyMode(prefs); + mKeyPreviewPopupDismissDelayRawValue = prefs.getString( + Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, + Integer.toString(res.getInteger(R.integer.config_key_preview_linger_timeout))); + mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true); + mAutoCorrectEnabled = isAutoCorrectEnabled(res, mAutoCorrectionThresholdRawValue); + mBigramSuggestionEnabled = mAutoCorrectEnabled + && isBigramSuggestionEnabled(prefs, res, mAutoCorrectEnabled); + mBigramPredictionEnabled = mBigramSuggestionEnabled + && isBigramPredictionEnabled(prefs, res); + mEnableSuggestionSpanInsertion = + prefs.getBoolean(Settings.PREF_KEY_ENABLE_SPAN_INSERT, true); + mVibrationDurationSettingsRawValue = + prefs.getInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, -1); + mKeypressSoundVolumeRawValue = prefs.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, -1.0f); + + // Compute other readable settings + mKeypressVibrationDuration = getCurrentVibrationDuration(prefs, res); + mFxVolume = getCurrentKeypressSoundVolume(prefs, res); + mKeyPreviewPopupDismissDelay = getKeyPreviewPopupDismissDelay(prefs, res); + mAutoCorrectionThreshold = getAutoCorrectionThreshold(res, + mAutoCorrectionThresholdRawValue); + mVoiceKeyEnabled = mVoiceMode != null && !mVoiceMode.equals(voiceModeOff); + mVoiceKeyOnMain = mVoiceMode != null && mVoiceMode.equals(voiceModeMain); + + LocaleUtils.setSystemLocale(res, savedLocale); + } + + // Helper functions to create member values. + private static String createSuggestPuncs(final String[] puncs) { + final StringBuilder sb = new StringBuilder(); + if (puncs != null) { + for (final String puncSpec : puncs) { + sb.append(KeySpecParser.getLabel(puncSpec)); + } + } + return sb.toString(); + } + + private static SuggestedWords createSuggestPuncList(final String[] puncs) { + final SuggestedWords.Builder builder = new SuggestedWords.Builder(); + if (puncs != null) { + for (final String puncSpec : puncs) { + builder.addWord(KeySpecParser.getLabel(puncSpec)); + } + } + return builder.setIsPunctuationSuggestions().build(); + } + + private static SuggestedWords createSuggestPuncOutputTextList(final String[] puncs) { + final SuggestedWords.Builder builder = new SuggestedWords.Builder(); + if (puncs != null) { + for (final String puncSpec : puncs) { + final String outputText = KeySpecParser.getOutputText(puncSpec); + if (outputText != null) { + builder.addWord(outputText); + } else { + builder.addWord(KeySpecParser.getLabel(puncSpec)); + } + } + } + return builder.setIsPunctuationSuggestions().build(); + } + + private static String createWordSeparators(final String magicSpaceStrippers, + final String magicSpaceSwappers, final String symbolsExcludedFromWordSeparators, + final Resources res) { + String wordSeparators = magicSpaceStrippers + magicSpaceSwappers + + res.getString(R.string.magic_space_promoting_symbols); + for (int i = symbolsExcludedFromWordSeparators.length() - 1; i >= 0; --i) { + wordSeparators = wordSeparators.replace( + symbolsExcludedFromWordSeparators.substring(i, i + 1), ""); + } + return wordSeparators; + } + + private static boolean isSettingsKeyShown(final SharedPreferences prefs, final Resources res) { + final boolean defaultShowSettingsKey = res.getBoolean( + R.bool.config_default_show_settings_key); + return isShowSettingsKeyOptionEnabled(res) + ? prefs.getBoolean(Settings.PREF_SHOW_SETTINGS_KEY, defaultShowSettingsKey) + : defaultShowSettingsKey; + } + + public static boolean isShowSettingsKeyOptionEnabled(final Resources resources) { + // TODO: Read this once and for all into a public final member + return resources.getBoolean(R.bool.config_enable_show_settings_key_option); + } + + private static boolean isVibrateOn(final Context context, final SharedPreferences prefs, + final Resources res) { + final boolean hasVibrator = VibratorCompatWrapper.getInstance(context).hasVibrator(); + return hasVibrator && prefs.getBoolean(Settings.PREF_VIBRATE_ON, + res.getBoolean(R.bool.config_default_vibration_enabled)); + } + + public boolean isWordSeparator(int code) { + return mWordSeparators.contains(String.valueOf((char)code)); + } + + public boolean isSymbolExcludedFromWordSeparators(int code) { + return mSymbolsExcludedFromWordSeparators.contains(String.valueOf((char)code)); + } + + public boolean isMagicSpaceStripper(int code) { + // TODO: this does not work if the code does not fit in a char + return mMagicSpaceStrippers.contains(String.valueOf((char)code)); + } + + public boolean isMagicSpaceSwapper(int code) { + // TODO: this does not work if the code does not fit in a char + return mMagicSpaceSwappers.contains(String.valueOf((char)code)); + } + + private static boolean isAutoCorrectEnabled(final Resources resources, + final String currentAutoCorrectionSetting) { + final String autoCorrectionOff = resources.getString( + R.string.auto_correction_threshold_mode_index_off); + return !currentAutoCorrectionSetting.equals(autoCorrectionOff); + } + + // Public to access from KeyboardSwitcher. Should it have access to some + // process-global instance instead? + public static boolean isKeyPreviewPopupEnabled(SharedPreferences sp, Resources resources) { + final boolean showPopupOption = resources.getBoolean( + R.bool.config_enable_show_popup_on_keypress_option); + if (!showPopupOption) return resources.getBoolean(R.bool.config_default_popup_preview); + return sp.getBoolean(Settings.PREF_POPUP_ON, + resources.getBoolean(R.bool.config_default_popup_preview)); + } + + // Likewise + public static int getKeyPreviewPopupDismissDelay(SharedPreferences sp, + Resources resources) { + // TODO: use mKeyPreviewPopupDismissDelayRawValue instead of reading it again here. + return Integer.parseInt(sp.getString(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, + Integer.toString(resources.getInteger( + R.integer.config_key_preview_linger_timeout)))); + } + + private static boolean isBigramSuggestionEnabled(final SharedPreferences sp, + final Resources resources, final boolean autoCorrectEnabled) { + final boolean showBigramSuggestionsOption = resources.getBoolean( + R.bool.config_enable_bigram_suggestions_option); + if (!showBigramSuggestionsOption) { + return autoCorrectEnabled; + } + return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTION, resources.getBoolean( + R.bool.config_default_bigram_suggestions)); + } + + private static boolean isBigramPredictionEnabled(final SharedPreferences sp, + final Resources resources) { + return sp.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, resources.getBoolean( + R.bool.config_default_bigram_prediction)); + } + + private static double getAutoCorrectionThreshold(final Resources resources, + final String currentAutoCorrectionSetting) { + final String[] autoCorrectionThresholdValues = resources.getStringArray( + R.array.auto_correction_threshold_values); + // When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off. + double autoCorrectionThreshold = Double.MAX_VALUE; + try { + final int arrayIndex = Integer.valueOf(currentAutoCorrectionSetting); + if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) { + autoCorrectionThreshold = Double.parseDouble( + autoCorrectionThresholdValues[arrayIndex]); + } + } catch (NumberFormatException e) { + // Whenever the threshold settings are correct, never come here. + autoCorrectionThreshold = Double.MAX_VALUE; + Log.w(TAG, "Cannot load auto correction threshold setting." + + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting + + ", autoCorrectionThresholdValues: " + + Arrays.toString(autoCorrectionThresholdValues)); + } + return autoCorrectionThreshold; + } + + public boolean isSettingsKeyEnabled() { + return mShowSettingsKey; + } + + public boolean isVoiceKeyEnabled(final EditorInfo editorInfo) { + final boolean shortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled(); + final int inputType = (editorInfo != null) ? editorInfo.inputType : 0; + return shortcutImeEnabled && mVoiceKeyEnabled + && !InputTypeCompatUtils.isPasswordInputType(inputType); + } + + public boolean isVoiceKeyOnMain() { + return mVoiceKeyOnMain; + } + + public boolean isFullscreenModeAllowed(Resources res) { + return res.getBoolean(R.bool.config_use_fullscreen_mode); + } + + // Accessed from the settings interface, hence public + public static float getCurrentKeypressSoundVolume(final SharedPreferences sp, + final Resources res) { + // TODO: use mVibrationDurationSettingsRawValue instead of reading it again here + final float volume = sp.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, -1.0f); + if (volume >= 0) { + return volume; + } + + final String[] volumePerHardwareList = res.getStringArray(R.array.keypress_volumes); + final String hardwarePrefix = Build.HARDWARE + ","; + for (final String element : volumePerHardwareList) { + if (element.startsWith(hardwarePrefix)) { + return Float.parseFloat(element.substring(element.lastIndexOf(',') + 1)); + } + } + return -1.0f; + } + + // Likewise + public static int getCurrentVibrationDuration(final SharedPreferences sp, + final Resources res) { + // TODO: use mKeypressVibrationDuration instead of reading it again here + final int ms = sp.getInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, -1); + if (ms >= 0) { + return ms; + } + final String[] durationPerHardwareList = res.getStringArray( + R.array.keypress_vibration_durations); + final String hardwarePrefix = Build.HARDWARE + ","; + for (final String element : durationPerHardwareList) { + if (element.startsWith(hardwarePrefix)) { + return (int)Long.parseLong(element.substring(element.lastIndexOf(',') + 1)); + } + } + return -1; + } + + // Likewise + public static boolean getUsabilityStudyMode(final SharedPreferences prefs) { + // TODO: use mUsabilityStudyMode instead of reading it again here + return prefs.getBoolean(Settings.PREF_USABILITY_STUDY_MODE, true); + } +} diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index 8a4862094..f5778167a 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -35,7 +35,6 @@ import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper; import com.android.inputmethod.deprecated.VoiceProxy; import com.android.inputmethod.keyboard.KeyboardSwitcher; -import com.android.inputmethod.keyboard.LatinKeyboard; import java.util.ArrayList; import java.util.Arrays; @@ -47,8 +46,8 @@ public class SubtypeSwitcher { private static boolean DBG = LatinImeLogger.sDBG; private static final String TAG = SubtypeSwitcher.class.getSimpleName(); + public static final String KEYBOARD_MODE = "keyboard"; private static final char LOCALE_SEPARATER = '_'; - private static final String KEYBOARD_MODE = "keyboard"; private static final String VOICE_MODE = "voice"; private static final String SUBTYPE_EXTRAVALUE_REQUIRE_NETWORK_CONNECTIVITY = "requireNetworkConnectivity"; @@ -421,11 +420,7 @@ public class SubtypeSwitcher { ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); mIsNetworkConnected = !noConnection; - final KeyboardSwitcher switcher = KeyboardSwitcher.getInstance(); - final LatinKeyboard keyboard = switcher.getLatinKeyboard(); - if (keyboard != null) { - keyboard.updateShortcutKey(isShortcutImeReady(), switcher.getKeyboardView()); - } + KeyboardSwitcher.getInstance().onNetworkStateChanged(); } ////////////////////////////////// diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index caa5aac51..f6e177aaf 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; @@ -42,9 +43,8 @@ public class Suggest implements Dictionary.WordCallback { public static final int APPROX_MAX_WORD_LENGTH = 32; public static final int CORRECTION_NONE = 0; - public static final int CORRECTION_BASIC = 1; - public static final int CORRECTION_FULL = 2; - public static final int CORRECTION_FULL_BIGRAM = 3; + public static final int CORRECTION_FULL = 1; + public static final int CORRECTION_FULL_BIGRAM = 2; /** * Words that appear in both bigram and unigram data gets multiplier ranging from @@ -101,13 +101,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 mCorrectionMode = CORRECTION_BASIC; + private int mTrailingSingleQuotesCount; public Suggest(final Context context, final int dictionaryResId, final Locale locale) { initAsynchronously(context, dictionaryResId, locale); @@ -116,7 +115,7 @@ public class Suggest implements Dictionary.WordCallback { /* package for test */ Suggest(final Context context, final File dictionary, final long startOffset, final long length, final Flag[] flagArray, final Locale locale) { - initSynchronously(null, DictionaryFactory.createDictionaryForTest(context, dictionary, + initSynchronously(context, DictionaryFactory.createDictionaryForTest(context, dictionary, startOffset, length, flagArray), locale); } @@ -144,7 +143,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) @@ -169,14 +168,6 @@ public class Suggest implements Dictionary.WordCallback { }.start(); } - public int getCorrectionMode() { - return mCorrectionMode; - } - - public void setCorrectionMode(int mode) { - mCorrectionMode = mode; - } - // The main dictionary could have been loaded asynchronously. Don't cache the return value // of this method. public boolean hasMainDictionary() { @@ -255,9 +246,10 @@ public class Suggest implements Dictionary.WordCallback { * @return suggested words object. */ public SuggestedWords getSuggestions(final WordComposer wordComposer, - final CharSequence prevWordForBigram, final ProximityInfo proximityInfo) { + final CharSequence prevWordForBigram, final ProximityInfo proximityInfo, + final int correctionMode) { return getSuggestedWordBuilder(wordComposer, prevWordForBigram, - proximityInfo).build(); + proximityInfo, correctionMode).build(); } private CharSequence capitalizeWord(boolean all, boolean first, CharSequence word) { @@ -290,25 +282,27 @@ public class Suggest implements Dictionary.WordCallback { // TODO: cleanup dictionaries looking up and suggestions building with SuggestedWords.Builder public SuggestedWords.Builder getSuggestedWordBuilder( final WordComposer wordComposer, CharSequence prevWordForBigram, - final ProximityInfo proximityInfo) { + final ProximityInfo proximityInfo, final int correctionMode) { LatinImeLogger.onStartSuggestion(prevWordForBigram); 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); + Dictionary.UNIGRAM); } - mTypedWord = typedWord; + mConsideredWord = consideredWord; - if (wordComposer.size() <= 1 && (mCorrectionMode == CORRECTION_FULL_BIGRAM - || mCorrectionMode == CORRECTION_BASIC)) { + if (wordComposer.size() <= 1 && (correctionMode == CORRECTION_FULL_BIGRAM)) { // At first character typed, search only the bigrams Arrays.fill(mBigramScores, 0); collectGarbage(mBigramSuggestions, PREF_MAX_BIGRAMS); @@ -321,7 +315,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 +324,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 +348,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, correctionMode, 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); @@ -406,12 +417,12 @@ public class Suggest implements Dictionary.WordCallback { @Override public boolean addWord(final char[] word, final int offset, final int length, int score, - final int dicTypeId, final Dictionary.DataType dataType) { - Dictionary.DataType dataTypeForLog = dataType; + final int dicTypeId, final int dataType) { + int dataTypeForLog = dataType; final ArrayList<CharSequence> suggestions; final int[] sortedScores; final int prefMaxSuggestions; - if(dataType == Dictionary.DataType.BIGRAM) { + if (dataType == Dictionary.BIGRAM) { suggestions = mBigramSuggestions; sortedScores = mBigramScores; prefMaxSuggestions = PREF_MAX_BIGRAMS; @@ -424,7 +435,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) { @@ -439,11 +450,11 @@ public class Suggest implements Dictionary.WordCallback { } } } else { - if (dataType == Dictionary.DataType.UNIGRAM) { + if (dataType == Dictionary.UNIGRAM) { // Check if the word was already added before (by bigram data) int bigramSuggestion = searchBigramSuggestion(word,offset,length); if(bigramSuggestion >= 0) { - dataTypeForLog = Dictionary.DataType.BIGRAM; + dataTypeForLog = Dictionary.BIGRAM; // turn freq from bigram into multiplier specified above double multiplier = (((double) mBigramScores[bigramSuggestion]) / MAXIMUM_BIGRAM_FREQUENCY) @@ -486,6 +497,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 +532,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/TextEntryState.java b/java/src/com/android/inputmethod/latin/TextEntryState.java deleted file mode 100644 index 79b3bdebb..000000000 --- a/java/src/com/android/inputmethod/latin/TextEntryState.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import com.android.inputmethod.keyboard.Keyboard; -import com.android.inputmethod.latin.Utils.RingCharBuffer; - -import android.util.Log; - -public class TextEntryState { - private static final String TAG = TextEntryState.class.getSimpleName(); - private static final boolean DEBUG = false; - - private static final int UNKNOWN = 0; - private static final int START = 1; - 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 int sState = UNKNOWN; - private static int sPreviousState = UNKNOWN; - - private static void setState(final int newState) { - sPreviousState = sState; - sState = newState; - } - - public static void acceptedDefault(CharSequence typedWord, CharSequence actualWord, - int separatorCode) { - if (typedWord == null) return; - setState(ACCEPTED_DEFAULT); - LatinImeLogger.logOnAutoCorrection( - typedWord.toString(), actualWord.toString(), separatorCode); - if (DEBUG) - displayState("acceptedDefault", "typedWord", typedWord, "actualWord", actualWord); - } - - // State.ACCEPTED_DEFAULT will be changed to other sub-states - // (see "case ACCEPTED_DEFAULT" in typedCharacter() below), - // and should be restored back to State.ACCEPTED_DEFAULT after processing for each sub-state. - public static void backToAcceptedDefault(CharSequence typedWord) { - if (typedWord == null) return; - switch (sState) { - case SPACE_AFTER_ACCEPTED: - case PUNCTUATION_AFTER_ACCEPTED: - case IN_WORD: - setState(ACCEPTED_DEFAULT); - break; - default: - break; - } - if (DEBUG) displayState("backToAcceptedDefault", "typedWord", typedWord); - } - - public static void acceptedTyped(CharSequence typedWord) { - setState(PICKED_SUGGESTION); - if (DEBUG) displayState("acceptedTyped", "typedWord", typedWord); - } - - public static void acceptedSuggestion(CharSequence typedWord, CharSequence actualWord) { - if (sState == RECORRECTING || sState == PICKED_RECORRECTION) { - setState(PICKED_RECORRECTION); - } else { - 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) { - case IN_WORD: - if (isSpace || isSeparator) { - setState(START); - } else { - // State hasn't changed. - } - break; - case ACCEPTED_DEFAULT: - case SPACE_AFTER_PICKED: - case PUNCTUATION_AFTER_ACCEPTED: - if (isSpace) { - setState(SPACE_AFTER_ACCEPTED); - } else if (isSeparator) { - // Swap - setState(PUNCTUATION_AFTER_ACCEPTED); - } else { - setState(IN_WORD); - } - break; - case PICKED_SUGGESTION: - case PICKED_RECORRECTION: - if (isSpace) { - setState(SPACE_AFTER_PICKED); - } else if (isSeparator) { - // Swap - setState(PUNCTUATION_AFTER_ACCEPTED); - } else { - setState(IN_WORD); - } - break; - case START: - case UNKNOWN: - case SPACE_AFTER_ACCEPTED: - case PUNCTUATION_AFTER_WORD: - if (!isSpace && !isSeparator) { - setState(IN_WORD); - } else { - setState(START); - } - break; - case UNDO_COMMIT: - if (isSpace || isSeparator) { - setState(START); - } else { - setState(IN_WORD); - } - break; - case RECORRECTING: - setState(START); - break; - } - RingCharBuffer.getInstance().push(c, x, y); - if (isSeparator) { - LatinImeLogger.logOnInputSeparator(); - } else { - LatinImeLogger.logOnInputChar(); - } - if (DEBUG) displayState("typedCharacter", "char", c, "isSeparator", isSeparator); - } - - public static void backspace() { - if (sState == ACCEPTED_DEFAULT) { - setState(UNDO_COMMIT); - LatinImeLogger.logOnAutoCorrectionCancelled(); - } else if (sState == UNDO_COMMIT) { - setState(IN_WORD); - } - if (DEBUG) displayState("backspace"); - } - - 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); - } - - private static String stateName(int state) { - switch (state) { - case START: return "START"; - 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"; - } - } - - private static void displayState(String title, Object ... args) { - final StringBuilder sb = new StringBuilder(title); - sb.append(':'); - for (int i = 0; i < args.length; i += 2) { - sb.append(' '); - sb.append(args[i]); - sb.append('='); - sb.append(args[i+1].toString()); - } - sb.append(" state="); - sb.append(stateName(sState)); - sb.append(" previous="); - sb.append(stateName(sPreviousState)); - Log.d(TAG, sb.toString()); - } -} diff --git a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java index 9e656675e..f80534cb5 100644 --- a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java @@ -159,7 +159,7 @@ public class UserBigramDictionary extends ExpandableDictionary { */ public int addBigrams(String word1, String word2) { // remove caps if second word is autocapitalized - if (mIme != null && mIme.getCurrentWord().isAutoCapitalized()) { + if (mIme != null && mIme.isAutoCapitalized()) { word2 = Character.toLowerCase(word2.charAt(0)) + word2.substring(1); } // Do not insert a word as a bigram of itself @@ -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..6d6296e10 100644 --- a/java/src/com/android/inputmethod/latin/UserDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserDictionary.java @@ -18,12 +18,10 @@ package com.android.inputmethod.latin; import android.content.ContentProviderClient; import android.content.ContentResolver; -import android.content.ContentValues; import android.content.Context; +import android.content.Intent; import android.database.ContentObserver; import android.database.Cursor; -import android.net.Uri; -import android.os.RemoteException; import android.provider.UserDictionary.Words; import android.text.TextUtils; @@ -38,11 +36,9 @@ public class UserDictionary extends ExpandableDictionary { Words.FREQUENCY, }; - private static final String[] PROJECTION_ADD = { - Words._ID, - Words.FREQUENCY, - Words.LOCALE, - }; + // This is not exported by the framework so we pretty much have to write it here verbatim + private static final String ACTION_USER_DICTIONARY_INSERT = + "com.android.settings.USER_DICTIONARY_INSERT"; private ContentObserver mObserver; final private String mLocale; @@ -134,7 +130,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() { @@ -160,54 +160,19 @@ public class UserDictionary extends ExpandableDictionary { public synchronized void addWord(final String word, final int frequency) { // Force load the dictionary here synchronously if (getRequiresReload()) loadDictionaryAsync(); + // TODO: do something for the UI. With the following, any sufficiently long word will + // look like it will go to the user dictionary but it won't. // Safeguard against adding long words. Can cause stack overflow. if (word.length() >= getMaxWordLength()) return; super.addWord(word, frequency); - // Update the user dictionary provider - final ContentValues values = new ContentValues(5); - values.put(Words.WORD, word); - values.put(Words.FREQUENCY, frequency); - values.put(Words.LOCALE, mLocale); - values.put(Words.APP_ID, 0); - - final ContentResolver contentResolver = getContext().getContentResolver(); - final ContentProviderClient client = - contentResolver.acquireContentProviderClient(Words.CONTENT_URI); - if (null == client) return; - new Thread("addWord") { - @Override - public void run() { - Cursor cursor = null; - try { - cursor = client.query(Words.CONTENT_URI, PROJECTION_ADD, - "word=? and ((locale IS NULL) or (locale=?))", - new String[] { word, mLocale }, null); - if (cursor != null && cursor.moveToFirst()) { - final String locale = cursor.getString(cursor.getColumnIndex(Words.LOCALE)); - // If locale is null, we will not override the entry. - if (locale != null && locale.equals(mLocale.toString())) { - final long id = cursor.getLong(cursor.getColumnIndex(Words._ID)); - final Uri uri = - Uri.withAppendedPath(Words.CONTENT_URI, Long.toString(id)); - // Update the entry with new frequency value. - client.update(uri, values, null, null); - } - } else { - // Insert new entry. - client.insert(Words.CONTENT_URI, values); - } - } catch (RemoteException e) { - // If we come here, the activity is already about to be killed, and we - // have no means of contacting the content provider any more. - // See ContentResolver#insert, inside the catch(){} - } finally { - if (null != cursor) cursor.close(); - client.release(); - } - } - }.start(); + // TODO: Add an argument to the intent to specify the frequency. + Intent intent = new Intent(ACTION_USER_DICTIONARY_INSERT); + intent.putExtra(Words.WORD, word); + intent.putExtra(Words.LOCALE, mLocale); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + getContext().startActivity(intent); // In case the above does a synchronous callback of the change observer setRequiresReload(false); @@ -242,6 +207,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..a7f57ae46 100644 --- a/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java @@ -149,7 +149,7 @@ public class UserUnigramDictionary extends ExpandableDictionary { final int length = word.length(); // Don't add very short or very long words. if (length < 2 || length > getMaxWordLength()) return; - if (mIme.getCurrentWord().isAutoCapitalized()) { + if (mIme.isAutoCapitalized()) { // Remove caps before adding word = Character.toLowerCase(word.charAt(0)) + word.substring(1); } @@ -172,7 +172,7 @@ public class UserUnigramDictionary extends ExpandableDictionary { // Nothing pending? Return if (mPendingWrites.isEmpty()) return; // Create a background thread to write the pending entries - new UpdateDbTask(getContext(), sOpenHelper, mPendingWrites, mLocale).execute(); + new UpdateDbTask(sOpenHelper, mPendingWrites, mLocale).execute(); // Create a new map for writing new entries into while the old one is written to db mPendingWrites = new HashMap<String, Integer>(); } @@ -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); @@ -227,8 +227,8 @@ public class UserUnigramDictionary extends ExpandableDictionary { private final DatabaseHelper mDbHelper; private final String mLocale; - public UpdateDbTask(@SuppressWarnings("unused") Context context, DatabaseHelper openHelper, - HashMap<String, Integer> pendingWrites, String locale) { + public UpdateDbTask(DatabaseHelper openHelper, HashMap<String, Integer> pendingWrites, + String locale) { mMap = pendingWrites; mLocale = locale; mDbHelper = openHelper; @@ -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..3975dddeb 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -17,11 +17,13 @@ package com.android.inputmethod.latin; import android.content.Context; -import android.content.SharedPreferences; +import android.content.Intent; +import android.content.pm.PackageManager; import android.content.res.Resources; import android.inputmethodservice.InputMethodService; +import android.net.Uri; import android.os.AsyncTask; -import android.os.Build; +import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; @@ -37,14 +39,17 @@ import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper; import com.android.inputmethod.compat.InputTypeCompatUtils; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.latin.define.JniLibName; import java.io.BufferedReader; import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; +import java.nio.channels.FileChannel; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; @@ -113,8 +118,9 @@ public class Utils { } public static boolean hasMultipleEnabledIMEsOrSubtypes( - final InputMethodManagerCompatWrapper imm, final boolean shouldIncludeAuxiliarySubtypes) { + final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance(); + if (imm == null) return false; final List<InputMethodInfoCompatWrapper> enabledImis = imm.getEnabledInputMethodList(); // Number of the filtered IMEs @@ -148,10 +154,21 @@ public class Utils { } } - return filteredImisCount > 1 - // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's enabled - // input method subtype (The current IME should be LatinIME.) - || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1; + if (filteredImisCount > 1) { + return true; + } + final List<InputMethodSubtypeCompatWrapper> subtypes = + imm.getEnabledInputMethodSubtypeList(null, true); + int keyboardCount = 0; + // imm.getEnabledInputMethodSubtypeList(null, true) will return the current IME's + // both explicitly and implicitly enabled input method subtype. + // (The current IME should be LatinIME.) + for (InputMethodSubtypeCompatWrapper subtype : subtypes) { + if (SubtypeSwitcher.KEYBOARD_MODE.equals(subtype.getMode())) { + ++keyboardCount; + } + } + return keyboardCount > 1; } public static String getInputMethodId(InputMethodManagerCompatWrapper imm, String packageName) { @@ -185,7 +202,8 @@ public class Utils { final int typedWordLength = typedWord.length(); final int maxEditDistanceOfNativeDictionary = (typedWordLength < 5 ? 2 : typedWordLength / 2) + 1; - final int distance = Utils.editDistance(typedWord, suggestionWord); + final int distance = BinaryDictionary.editDistance( + typedWord.toString(), suggestionWord.toString()); if (DBG) { Log.d(TAG, "Autocorrected edit distance = " + distance + ", " + maxEditDistanceOfNativeDictionary); @@ -242,7 +260,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; } @@ -317,49 +335,6 @@ public class Utils { } } - - /* Damerau-Levenshtein distance */ - public static int editDistance(CharSequence s, CharSequence t) { - if (s == null || t == null) { - throw new IllegalArgumentException("editDistance: Arguments should not be null."); - } - final int sl = s.length(); - final int tl = t.length(); - int[][] dp = new int [sl + 1][tl + 1]; - for (int i = 0; i <= sl; i++) { - dp[i][0] = i; - } - for (int j = 0; j <= tl; j++) { - dp[0][j] = j; - } - for (int i = 0; i < sl; ++i) { - for (int j = 0; j < tl; ++j) { - final char sc = Character.toLowerCase(s.charAt(i)); - final char tc = Character.toLowerCase(t.charAt(j)); - final int cost = sc == tc ? 0 : 1; - dp[i + 1][j + 1] = Math.min( - dp[i][j + 1] + 1, Math.min(dp[i + 1][j] + 1, dp[i][j] + cost)); - // Overwrite for transposition cases - if (i > 0 && j > 0 - && sc == Character.toLowerCase(t.charAt(j - 1)) - && tc == Character.toLowerCase(s.charAt(i - 1))) { - dp[i + 1][j + 1] = Math.min(dp[i + 1][j + 1], dp[i - 1][j - 1] + cost); - } - } - } - if (DBG_EDIT_DISTANCE) { - Log.d(TAG, "editDistance:" + s + "," + t); - for (int i = 0; i < dp.length; ++i) { - StringBuffer sb = new StringBuffer(); - for (int j = 0; j < dp[i].length; ++j) { - sb.append(dp[i][j]).append(','); - } - Log.d(TAG, i + ":" + sb.toString()); - } - } - return dp[sl][tl]; - } - // Get the current stack trace public static String getStackTrace() { StringBuilder sb = new StringBuilder(); @@ -373,55 +348,6 @@ public class Utils { return sb.toString(); } - // In dictionary.cpp, getSuggestion() method, - // suggestion scores are computed using the below formula. - // original score - // := pow(mTypedLetterMultiplier (this is defined 2), - // (the number of matched characters between typed word and suggested word)) - // * (individual word's score which defined in the unigram dictionary, - // and this score is defined in range [0, 255].) - // Then, the following processing is applied. - // - If the dictionary word is matched up to the point of the user entry - // (full match up to min(before.length(), after.length()) - // => Then multiply by FULL_MATCHED_WORDS_PROMOTION_RATE (this is defined 1.2) - // - If the word is a true full match except for differences in accents or - // capitalization, then treat it as if the score was 255. - // - If before.length() == after.length() - // => multiply by mFullWordMultiplier (this is defined 2)) - // So, maximum original score is pow(2, min(before.length(), after.length())) * 255 * 2 * 1.2 - // For historical reasons we ignore the 1.2 modifier (because the measure for a good - // autocorrection threshold was done at a time when it didn't exist). This doesn't change - // the result. - // So, we can normalize original score by dividing pow(2, min(b.l(),a.l())) * 255 * 2. - private static final int MAX_INITIAL_SCORE = 255; - private static final int TYPED_LETTER_MULTIPLIER = 2; - private static final int FULL_WORD_MULTIPLIER = 2; - private static final int S_INT_MAX = 2147483647; - public static double calcNormalizedScore(CharSequence before, CharSequence after, int score) { - final int beforeLength = before.length(); - final int afterLength = after.length(); - if (beforeLength == 0 || afterLength == 0) return 0; - final int distance = editDistance(before, after); - // If afterLength < beforeLength, the algorithm is suggesting a word by excessive character - // correction. - int spaceCount = 0; - for (int i = 0; i < afterLength; ++i) { - if (after.charAt(i) == Keyboard.CODE_SPACE) { - ++spaceCount; - } - } - if (spaceCount == afterLength) return 0; - final double maximumScore = score == S_INT_MAX ? S_INT_MAX : MAX_INITIAL_SCORE - * Math.pow( - TYPED_LETTER_MULTIPLIER, Math.min(beforeLength, afterLength - spaceCount)) - * FULL_WORD_MULTIPLIER; - // add a weight based on edit distance. - // distance <= max(afterLength, beforeLength) == afterLength, - // so, 0 <= distance / afterLength <= 1 - final double weight = 1.0 - (double) distance / afterLength; - return (score / maximumScore) * weight; - } - public static class UsabilityStudyLogUtils { private static final String USABILITY_TAG = UsabilityStudyLogUtils.class.getSimpleName(); private static final String FILENAME = "log.txt"; @@ -437,7 +363,7 @@ public class Utils { private UsabilityStudyLogUtils() { mDate = new Date(); - mDateFormat = new SimpleDateFormat("dd MMM HH:mm:ss.SSS"); + mDateFormat = new SimpleDateFormat("yyyyMMdd-HHmmss.SSSZ"); HandlerThread handlerThread = new HandlerThread("UsabilityStudyLogUtils logging task", Process.THREAD_PRIORITY_BACKGROUND); @@ -465,7 +391,7 @@ public class Utils { } } - public void writeBackSpace() { + public static void writeBackSpace() { UsabilityStudyLogUtils.getInstance().write("<backspace>\t0\t0"); } @@ -504,32 +430,89 @@ public class Utils { }); } - public void printAll() { + private synchronized String getBufferedLogs() { + mWriter.flush(); + StringBuilder sb = new StringBuilder(); + BufferedReader br = getBufferedReader(); + String line; + try { + while ((line = br.readLine()) != null) { + sb.append('\n'); + sb.append(line); + } + } catch (IOException e) { + Log.e(USABILITY_TAG, "Can't read log file."); + } finally { + if (LatinImeLogger.sDBG) { + Log.d(USABILITY_TAG, "Got all buffered logs\n" + sb.toString()); + } + try { + br.close(); + } catch (IOException e) { + // ignore. + } + } + return sb.toString(); + } + + public void emailResearcherLogsAll() { mLoggingHandler.post(new Runnable() { @Override public void run() { + final Date date = new Date(); + date.setTime(System.currentTimeMillis()); + final String currentDateTimeString = + new SimpleDateFormat("yyyyMMdd-HHmmssZ").format(date); + if (mFile == null) { + Log.w(USABILITY_TAG, "No internal log file found."); + return; + } + if (mIms.checkCallingOrSelfPermission( + android.Manifest.permission.WRITE_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) { + Log.w(USABILITY_TAG, "Doesn't have the permission WRITE_EXTERNAL_STORAGE"); + return; + } mWriter.flush(); - StringBuilder sb = new StringBuilder(); - BufferedReader br = getBufferedReader(); - String line; + final String destPath = Environment.getExternalStorageDirectory() + + "/research-" + currentDateTimeString + ".log"; + final File destFile = new File(destPath); try { - while ((line = br.readLine()) != null) { - sb.append('\n'); - sb.append(line); - } - } catch (IOException e) { - Log.e(USABILITY_TAG, "Can't read log file."); - } finally { - if (LatinImeLogger.sDBG) { - Log.d(USABILITY_TAG, "output all logs\n" + sb.toString()); - } - mIms.getCurrentInputConnection().commitText(sb.toString(), 0); - try { - br.close(); - } catch (IOException e) { - // ignore. - } + final FileChannel src = (new FileInputStream(mFile)).getChannel(); + final FileChannel dest = (new FileOutputStream(destFile)).getChannel(); + src.transferTo(0, src.size(), dest); + src.close(); + dest.close(); + } catch (FileNotFoundException e1) { + Log.w(USABILITY_TAG, e1); + return; + } catch (IOException e2) { + Log.w(USABILITY_TAG, e2); + return; } + if (destFile == null || !destFile.exists()) { + Log.w(USABILITY_TAG, "Dest file doesn't exist."); + return; + } + final Intent intent = new Intent(Intent.ACTION_SEND); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + if (LatinImeLogger.sDBG) { + Log.d(USABILITY_TAG, "Destination file URI is " + destFile.toURI()); + } + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + destPath)); + intent.putExtra(Intent.EXTRA_SUBJECT, + "[Research Logs] " + currentDateTimeString); + mIms.startActivity(intent); + } + }); + } + + public void printAll() { + mLoggingHandler.post(new Runnable() { + @Override + public void run() { + mIms.getCurrentInputConnection().commitText(getBufferedLogs(), 0); } }); } @@ -630,9 +613,13 @@ public class Utils { public static void loadNativeLibrary() { try { - System.loadLibrary("jni_latinime"); + System.loadLibrary(JniLibName.JNI_LIB_NAME); } catch (UnsatisfiedLinkError ule) { - Log.e(TAG, "Could not load native library jni_latinime"); + Log.e(TAG, "Could not load native library " + JniLibName.JNI_LIB_NAME); + if (LatinImeLogger.sDBG) { + throw new RuntimeException( + "Could not load native library " + JniLibName.JNI_LIB_NAME); + } } } @@ -778,40 +765,37 @@ public class Utils { return s.toUpperCase(locale).charAt(0) + s.substring(1); } - public static int getCurrentVibrationDuration(SharedPreferences sp, Resources res) { - final int ms = sp.getInt(Settings.PREF_KEYPRESS_VIBRATION_DURATION_SETTINGS, -1); - if (ms >= 0) { - return ms; - } - final String[] durationPerHardwareList = res.getStringArray( - R.array.keypress_vibration_durations); - final String hardwarePrefix = Build.HARDWARE + ","; - for (final String element : durationPerHardwareList) { - if (element.startsWith(hardwarePrefix)) { - return (int)Long.parseLong(element.substring(element.lastIndexOf(',') + 1)); - } - } - return -1; + public static boolean willAutoCorrect(SuggestedWords suggestions) { + return !suggestions.mTypedWordValid && suggestions.mHasAutoCorrectionCandidate + && !suggestions.shouldBlockAutoCorrection(); } - public static float getCurrentKeypressSoundVolume(SharedPreferences sp, Resources res) { - final float volume = sp.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, -1.0f); - if (volume >= 0) { - return volume; + public static class Stats { + public static void onNonSeparator(final char code, final int x, + final int y) { + RingCharBuffer.getInstance().push(code, x, y); + LatinImeLogger.logOnInputChar(); } - final String[] volumePerHardwareList = res.getStringArray(R.array.keypress_volumes); - final String hardwarePrefix = Build.HARDWARE + ","; - for (final String element : volumePerHardwareList) { - if (element.startsWith(hardwarePrefix)) { - return Float.parseFloat(element.substring(element.lastIndexOf(',') + 1)); - } + public static void onSeparator(final char code, final int x, + final int y) { + RingCharBuffer.getInstance().push(code, x, y); + LatinImeLogger.logOnInputSeparator(); + } + + public static void onAutoCorrection(final String typedWord, final String correctedWord, + final int separatorCode) { + if (TextUtils.isEmpty(typedWord)) return; + LatinImeLogger.logOnAutoCorrection(typedWord, correctedWord, separatorCode); + } + + public static void onAutoCorrectionCancellation() { + LatinImeLogger.logOnAutoCorrectionCancelled(); } - return -1.0f; } - public static boolean willAutoCorrect(SuggestedWords suggestions) { - return !suggestions.mTypedWordValid && suggestions.mHasAutoCorrectionCandidate - && !suggestions.shouldBlockAutoCorrection(); + public static int codePointCount(String text) { + if (TextUtils.isEmpty(text)) return 0; + return text.codePointCount(0, text.length()); } } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index adc5637f6..a1a329a8d 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2008 The Android Open Source Project - * + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -16,9 +16,12 @@ package com.android.inputmethod.latin; +import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.KeyDetector; +import com.android.inputmethod.keyboard.Keyboard; 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 @@ -28,31 +31,31 @@ public class WordComposer { public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE; public static final int NOT_A_COORDINATE = -1; - /** - * The list of unicode values for each keystroke (including surrounding keys) - */ - private ArrayList<int[]> mCodes; + final static int N = BinaryDictionary.MAX_WORD_LENGTH; + private ArrayList<int[]> mCodes; private int[] mXCoordinates; private int[] mYCoordinates; - private StringBuilder mTypedWord; + private CharSequence mAutoCorrection; + // Cache these values for performance private int mCapsCount; - private boolean mAutoCapitalized; - + private int mTrailingSingleQuotesCount; + /** * Whether the user chose to capitalize the first char of the word. */ private boolean mIsFirstCharCapitalized; public WordComposer() { - final int N = BinaryDictionary.MAX_WORD_LENGTH; mCodes = new ArrayList<int[]>(N); mTypedWord = new StringBuilder(N); mXCoordinates = new int[N]; mYCoordinates = new int[N]; + mAutoCorrection = null; + mTrailingSingleQuotesCount = 0; } public WordComposer(WordComposer source) { @@ -62,11 +65,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; } /** @@ -75,8 +79,10 @@ public class WordComposer { public void reset() { mCodes.clear(); mTypedWord.setLength(0); + mAutoCorrection = null; mCapsCount = 0; mIsFirstCharCapitalized = false; + mTrailingSingleQuotesCount = 0; } /** @@ -84,7 +90,11 @@ public class WordComposer { * @return the number of keystrokes */ public final int size() { - return mTypedWord.length(); + return mCodes.size(); + } + + public final boolean isComposingWord() { + return mCodes.size() > 0; } /** @@ -115,8 +125,8 @@ public class WordComposer { * @param codes the array of unicode values */ public void add(int primaryCode, int[] codes, int x, int y) { - final int newIndex = size(); - mTypedWord.append((char) primaryCode); + final int newIndex = mCodes.size(); + mTypedWord.appendCodePoint(primaryCode); correctPrimaryJuxtapos(primaryCode, codes); mCodes.add(codes); if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) { @@ -126,6 +136,56 @@ public class WordComposer { mIsFirstCharCapitalized = isFirstCharCapitalized( newIndex, primaryCode, mIsFirstCharCapitalized); if (Character.isUpperCase(primaryCode)) mCapsCount++; + if (Keyboard.CODE_SINGLE_QUOTE == primaryCode) { + ++mTrailingSingleQuotesCount; + } else { + mTrailingSingleQuotesCount = 0; + } + mAutoCorrection = null; + } + + /** + * Internal method to retrieve reasonable proximity info for a character. + */ + private void addKeyInfo(final int codePoint, final Keyboard 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 Keyboard keyboard, + final KeyDetector keyDetector) { + reset(); + final int length = word.length(); + for (int i = 0; i < length; i = Character.offsetByCodePoints(word, i, 1)) { + int codePoint = Character.codePointAt(word, 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 Keyboard 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 +195,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]; @@ -147,27 +207,45 @@ public class WordComposer { * Delete the last keystroke as a result of hitting backspace. */ public void deleteLast() { - final int size = size(); + final int size = mCodes.size(); if (size > 0) { - final int lastPos = size - 1; - char lastChar = mTypedWord.charAt(lastPos); - mCodes.remove(lastPos); - mTypedWord.deleteCharAt(lastPos); + mCodes.remove(size - 1); + // Note: mTypedWord.length() and mCodes.length differ when there are surrogate pairs + final int stringBuilderLength = mTypedWord.length(); + if (stringBuilderLength < size) { + throw new RuntimeException( + "In WordComposer: mCodes and mTypedWords have non-matching lengths"); + } + final int lastChar = mTypedWord.codePointBefore(stringBuilderLength); + if (Character.isSupplementaryCodePoint(lastChar)) { + mTypedWord.delete(stringBuilderLength - 2, stringBuilderLength); + } else { + mTypedWord.deleteCharAt(stringBuilderLength - 1); + } if (Character.isUpperCase(lastChar)) mCapsCount--; } - if (size() == 0) { + // We may have deleted the last one. + if (0 == mCodes.size()) { mIsFirstCharCapitalized = false; } + if (mTrailingSingleQuotesCount > 0) { + --mTrailingSingleQuotesCount; + } else { + int i = mTypedWord.length(); + while (i > 0) { + i = mTypedWord.offsetByCodePoints(i, -1); + if (Keyboard.CODE_SINGLE_QUOTE != mTypedWord.codePointAt(i)) break; + ++mTrailingSingleQuotesCount; + } + } + mAutoCorrection = null; } /** * Returns the word as it was typed, without any correction applied. - * @return the word that was typed so far + * @return the word that was typed so far. Never returns null. */ public String getTypedWord() { - if (size() == 0) { - return null; - } return mTypedWord.toString(); } @@ -179,6 +257,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 @@ -194,7 +276,7 @@ public class WordComposer { return mCapsCount > 1; } - /** + /** * Saves the reason why the word is capitalized - whether it was automatic or * due to the user hitting shift in the middle of a sentence. * @param auto whether it was an automatic capitalization due to start of sentence @@ -210,4 +292,56 @@ public class WordComposer { public boolean isAutoCapitalized() { return mAutoCapitalized; } + + /** + * Sets the auto-correction for this word. + */ + public void setAutoCorrection(final CharSequence correction) { + mAutoCorrection = correction; + } + + /** + * @return the auto-correction for this word, or null if none. + */ + public CharSequence getAutoCorrectionOrNull() { + return mAutoCorrection; + } + + // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above. + public LastComposedWord commitWord(final int type) { + // Note: currently, we come here whenever we commit a word. If it's any *other* kind than + // DECIDED_WORD, we should reset mAutoCorrection so that we don't attempt to cancel later. + // If it's a DECIDED_WORD, it may be an actual auto-correction by the IME, or what the user + // typed because the IME decided *not* to auto-correct for whatever reason. + // Ideally we would also null it when it was a DECIDED_WORD that was not an auto-correct. + // As it happens these two cases should behave differently, because the former can be + // canceled while the latter can't. Currently, we figure this out in + // LastComposedWord#didAutoCorrectToAnotherWord with #equals(). It would be marginally + // cleaner to do it here, but it would be slower (since we would #equals() for each commit, + // instead of only on cancel), and ultimately we want to figure it out even earlier anyway. + final ArrayList<int[]> codes = mCodes; + final int[] xCoordinates = mXCoordinates; + final int[] yCoordinates = mYCoordinates; + mCodes = new ArrayList<int[]>(N); + mXCoordinates = new int[N]; + mYCoordinates = new int[N]; + final LastComposedWord lastComposedWord = new LastComposedWord(codes, + xCoordinates, yCoordinates, mTypedWord.toString(), + null == mAutoCorrection ? null : mAutoCorrection.toString()); + if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD) { + lastComposedWord.deactivate(); + } + mTypedWord.setLength(0); + mAutoCorrection = null; + return lastComposedWord; + } + + public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord) { + mCodes = lastComposedWord.mCodes; + mXCoordinates = lastComposedWord.mXCoordinates; + mYCoordinates = lastComposedWord.mYCoordinates; + mTypedWord.setLength(0); + mTypedWord.append(lastComposedWord.mTypedWord); + mAutoCorrection = lastComposedWord.mAutoCorrection; + } } diff --git a/java/src/com/android/inputmethod/latin/XmlParseUtils.java b/java/src/com/android/inputmethod/latin/XmlParseUtils.java new file mode 100644 index 000000000..d747a024c --- /dev/null +++ b/java/src/com/android/inputmethod/latin/XmlParseUtils.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin; + +import android.content.res.TypedArray; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +public class XmlParseUtils { + @SuppressWarnings("serial") + public static class ParseException extends XmlPullParserException { + public ParseException(String msg, XmlPullParser parser) { + super(msg + " at line " + parser.getLineNumber() + + ", column " + parser.getColumnNumber()); + } + } + + @SuppressWarnings("serial") + public static class IllegalStartTag extends ParseException { + public IllegalStartTag(XmlPullParser parser, String parent) { + super("Illegal start tag " + parser.getName() + " in " + parent, parser); + } + } + + @SuppressWarnings("serial") + public static class IllegalEndTag extends ParseException { + public IllegalEndTag(XmlPullParser parser, String parent) { + super("Illegal end tag " + parser.getName() + " in " + parent, parser); + } + } + + @SuppressWarnings("serial") + public static class IllegalAttribute extends ParseException { + public IllegalAttribute(XmlPullParser parser, String attribute) { + super("Tag " + parser.getName() + " has illegal attribute " + attribute, parser); + } + } + + @SuppressWarnings("serial") + public static class NonEmptyTag extends ParseException{ + public NonEmptyTag(String tag, XmlPullParser parser) { + super(tag + " must be empty tag", parser); + } + } + + public static void checkEndTag(String tag, XmlPullParser parser) + throws XmlPullParserException, IOException { + if (parser.next() == XmlPullParser.END_TAG && tag.equals(parser.getName())) + return; + throw new NonEmptyTag(tag, parser); + } + + public static void checkAttributeExists(TypedArray attr, int attrId, String attrName, + String tag, XmlPullParser parser) throws XmlPullParserException { + if (attr.hasValue(attrId)) + return; + throw new ParseException( + "No " + attrName + " attribute found in <" + tag + "/>", parser); + } +} diff --git a/java/src/com/android/inputmethod/latin/define/JniLibName.java b/java/src/com/android/inputmethod/latin/define/JniLibName.java new file mode 100644 index 000000000..3e94a3c07 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/define/JniLibName.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin.define; + +public class JniLibName { + public static final String JNI_LIB_NAME = "jni_latinime"; +} diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 095c2c51c..8ac82ee5b 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; @@ -25,10 +27,10 @@ import android.view.textservice.SuggestionsInfo; import android.view.textservice.TextInfo; import com.android.inputmethod.compat.ArraysCompatUtils; +import com.android.inputmethod.compat.SuggestionsInfoCompatUtils; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.BinaryDictionary; import com.android.inputmethod.latin.Dictionary; -import com.android.inputmethod.latin.Dictionary.DataType; import com.android.inputmethod.latin.Dictionary.WordCallback; import com.android.inputmethod.latin.DictionaryCollection; import com.android.inputmethod.latin.DictionaryFactory; @@ -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,100 @@ 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>>(); + + public static final int SCRIPT_LATIN = 0; + public 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); + } @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); + } + + private static int getScriptFromLocale(final Locale locale) { + final Integer script = mLanguageToScript.get(locale.getLanguage()); + if (null == script) { + throw new RuntimeException("We have been called with an unsupported language: \"" + + locale.getLanguage() + "\". Framework bug?"); + } + return script; + } + + @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 +203,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 +215,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 +225,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]; @@ -142,7 +236,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService { @Override synchronized public boolean addWord(char[] word, int wordOffset, int wordLength, int score, - int dicTypeId, DataType dataType) { + int dicTypeId, int dataType) { final int positionIndex = ArraysCompatUtils.binarySearch(mScores, 0, mLength, score); // binarySearch returns the index if the element exists, and -<insertion index> - 1 // if it doesn't. See documentation for binarySearch. @@ -175,7 +269,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService { // make the threshold. final String wordString = new String(word, wordOffset, wordLength); final double normalizedScore = - Utils.calcNormalizedScore(mOriginalText, wordString, score); + BinaryDictionary.calcNormalizedScore(mOriginalText, wordString, score); if (normalizedScore < mSuggestionThreshold) { if (DBG) Log.i(TAG, wordString + " does not make the score threshold"); return true; @@ -198,19 +292,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); + final double normalizedScore = BinaryDictionary.calcNormalizedScore( + mOriginalText, mBestSuggestion, mBestScore); + hasRecommendedSuggestions = (normalizedScore > mRecommendedThreshold); } } else { if (DBG) { @@ -243,16 +337,17 @@ public class AndroidSpellCheckerService extends SpellCheckerService { final int bestScore = mScores[mLength - 1]; final CharSequence bestSuggestion = mSuggestions.get(0); final double normalizedScore = - Utils.calcNormalizedScore(mOriginalText, bestSuggestion, bestScore); - hasLikelySuggestions = (normalizedScore > mLikelyThreshold); + BinaryDictionary.calcNormalizedScore( + mOriginalText, bestSuggestion.toString(), bestScore); + 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 +368,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; } @@ -295,7 +392,9 @@ public class AndroidSpellCheckerService extends SpellCheckerService { } public DictAndProximity createDictAndProximity(final Locale locale) { - final ProximityInfo proximityInfo = ProximityInfo.createSpellCheckerProximityInfo(); + final int script = getScriptFromLocale(locale); + final ProximityInfo proximityInfo = ProximityInfo.createSpellCheckerProximityInfo( + SpellCheckerProximityInfo.getProximityForScript(script)); final Resources resources = getResources(); final int fallbackResourceId = Utils.getMainDictionaryResourceId(resources); final DictionaryCollection dictionaryCollection = @@ -314,11 +413,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); } @@ -327,9 +431,9 @@ public class AndroidSpellCheckerService extends SpellCheckerService { // If the first char is not uppercase, then the word is either all lower case, // and in either case we return CAPITALIZE_NONE. if (!Character.isUpperCase(text.codePointAt(0))) return CAPITALIZE_NONE; - final int len = text.codePointCount(0, text.length()); + final int len = text.length(); int capsCount = 1; - for (int i = 1; i < len; ++i) { + for (int i = 1; i < len; i = text.offsetByCodePoints(i, 1)) { if (1 != capsCount && i != capsCount) break; if (Character.isUpperCase(text.codePointAt(i))) ++capsCount; } @@ -346,6 +450,8 @@ public class AndroidSpellCheckerService extends SpellCheckerService { 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 +464,51 @@ public class AndroidSpellCheckerService extends SpellCheckerService { final String localeString = getLocale(); mDictionaryPool = mService.getDictionaryPool(localeString); mLocale = LocaleUtils.constructLocaleFromString(localeString); + mScript = getScriptFromLocale(mLocale); + } + + /* + * 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,20 +516,19 @@ 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 final int length = text.length(); int letterCount = 0; - for (int i = 0; i < length; ++i) { + for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) { final int codePoint = text.codePointAt(i); // Any word containing a '@' is probably an e-mail address // Any word containing a '/' is probably either an ad-hoc combination of two // 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 ('@' == codePoint || '/' == codePoint) return true; + 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 +547,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,17 +565,23 @@ 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) { + for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) { final int character = text.codePointAt(i); - final int proximityIndex = SpellCheckerProximityInfo.getIndexOf(character); + final int proximityIndex = + SpellCheckerProximityInfo.getIndexOfCodeForScript(character, mScript); final int[] proximities; if (-1 == proximityIndex) { proximities = new int[] { character }; } else { - proximities = Arrays.copyOfRange(SpellCheckerProximityInfo.PROXIMITY, + // TODO: an initial examination seems to reveal this is actually used + // read-only. It should be possible to compute the arrays statically once + // and skip doing a copy each time here. + proximities = Arrays.copyOfRange( + SpellCheckerProximityInfo.getProximityForScript(mScript), proximityIndex, proximityIndex + SpellCheckerProximityInfo.ROW_SIZE); } @@ -475,7 +620,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 +628,13 @@ 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 + ? SuggestionsInfoCompatUtils + .getValueOf_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 diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java index d5b04b27c..db3544987 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java @@ -22,72 +22,158 @@ import com.android.inputmethod.keyboard.ProximityInfo; import java.util.TreeMap; public class SpellCheckerProximityInfo { - final private static int NUL = KeyDetector.NOT_A_CODE; + /* public for test */ + final public static int NUL = KeyDetector.NOT_A_CODE; // This must be the same as MAX_PROXIMITY_CHARS_SIZE else it will not work inside // native code - this value is passed at creation of the binary object and reused // as the size of the passed array afterwards so they can't be different. final public static int ROW_SIZE = ProximityInfo.MAX_PROXIMITY_CHARS_SIZE; - // This is a map from the code point to the index in the PROXIMITY array. - // At the time the native code to read the binary dictionary needs the proximity info be passed - // as a flat array spaced by MAX_PROXIMITY_CHARS_SIZE columns, one for each input character. - // Since we need to build such an array, we want to be able to search in our big proximity data - // quickly by character, and a map is probably the best way to do this. - final private static TreeMap<Integer, Integer> INDICES = new TreeMap<Integer, Integer>(); + // Helper methods + final protected static void buildProximityIndices(final int[] proximity, + final TreeMap<Integer, Integer> indices) { + for (int i = 0; i < proximity.length; i += ROW_SIZE) { + if (NUL != proximity[i]) indices.put(proximity[i], i); + } + } + final protected static int computeIndex(final int characterCode, + final TreeMap<Integer, Integer> indices) { + final Integer result = indices.get(characterCode); + if (null == result) return -1; + return result; + } - // The proximity here is the union of - // - the proximity for a QWERTY keyboard. - // - the proximity for an AZERTY keyboard. - // - the proximity for a QWERTZ keyboard. - // ...plus, add all characters in the ('a', 'e', 'i', 'o', 'u') set to each other. - // - // The reasoning behind this construction is, almost any alphabetic text we may want - // to spell check has been entered with one of the keyboards above. Also, specifically - // to English, many spelling errors consist of the last vowel of the word being wrong - // because in English vowels tend to merge with each other in pronunciation. - final public static int[] PROXIMITY = { - 'q', 'w', 's', 'a', 'z', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'w', 'q', 'a', 's', 'd', 'e', 'x', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'e', 'w', 's', 'd', 'f', 'r', 'a', 'i', 'o', 'u', NUL, NUL, NUL, NUL, NUL, NUL, - 'r', 'e', 'd', 'f', 'g', 't', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 't', 'r', 'f', 'g', 'h', 'y', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'y', 't', 'g', 'h', 'j', 'u', 'a', 's', 'd', 'x', NUL, NUL, NUL, NUL, NUL, NUL, - 'u', 'y', 'h', 'j', 'k', 'i', 'a', 'e', 'o', NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'i', 'u', 'j', 'k', 'l', 'o', 'a', 'e', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'o', 'i', 'k', 'l', 'p', 'a', 'e', 'u', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'p', 'o', 'l', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + private static class Latin { + // This is a map from the code point to the index in the PROXIMITY array. + // At the time the native code to read the binary dictionary needs the proximity info be + // passed as a flat array spaced by MAX_PROXIMITY_CHARS_SIZE columns, one for each input + // character. + // Since we need to build such an array, we want to be able to search in our big proximity + // data quickly by character, and a map is probably the best way to do this. + final private static TreeMap<Integer, Integer> INDICES = new TreeMap<Integer, Integer>(); - 'a', 'z', 'x', 's', 'w', 'q', 'e', 'i', 'o', 'u', NUL, NUL, NUL, NUL, NUL, NUL, - 's', 'q', 'a', 'z', 'x', 'c', 'd', 'e', 'w', NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'd', 'w', 's', 'x', 'c', 'v', 'f', 'r', 'e', 'w', NUL, NUL, NUL, NUL, NUL, NUL, - 'f', 'e', 'd', 'c', 'v', 'b', 'g', 't', 'r', NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'g', 'r', 'f', 'v', 'b', 'n', 'h', 'y', 't', NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'h', 't', 'g', 'b', 'n', 'm', 'j', 'u', 'y', NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'j', 'y', 'h', 'n', 'm', 'k', 'i', 'u', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'k', 'u', 'j', 'm', 'l', 'o', 'i', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'l', 'i', 'k', 'p', 'o', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + // The proximity here is the union of + // - the proximity for a QWERTY keyboard. + // - the proximity for an AZERTY keyboard. + // - the proximity for a QWERTZ keyboard. + // ...plus, add all characters in the ('a', 'e', 'i', 'o', 'u') set to each other. + // + // The reasoning behind this construction is, almost any alphabetic text we may want + // to spell check has been entered with one of the keyboards above. Also, specifically + // to English, many spelling errors consist of the last vowel of the word being wrong + // because in English vowels tend to merge with each other in pronunciation. + final static int[] PROXIMITY = { + 'q', 'w', 's', 'a', 'z', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'w', 'q', 'a', 's', 'd', 'e', 'x', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'e', 'w', 's', 'd', 'f', 'r', 'a', 'i', 'o', 'u', NUL, NUL, NUL, NUL, NUL, NUL, + 'r', 'e', 'd', 'f', 'g', 't', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 't', 'r', 'f', 'g', 'h', 'y', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'y', 't', 'g', 'h', 'j', 'u', 'a', 's', 'd', 'x', NUL, NUL, NUL, NUL, NUL, NUL, + 'u', 'y', 'h', 'j', 'k', 'i', 'a', 'e', 'o', NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'i', 'u', 'j', 'k', 'l', 'o', 'a', 'e', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'o', 'i', 'k', 'l', 'p', 'a', 'e', 'u', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'p', 'o', 'l', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'z', 'a', 's', 'd', 'x', 't', 'g', 'h', 'j', 'u', 'q', 'e', NUL, NUL, NUL, NUL, - 'x', 'z', 'a', 's', 'd', 'c', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'c', 'x', 's', 'd', 'f', 'v', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'v', 'c', 'd', 'f', 'g', 'b', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'b', 'v', 'f', 'g', 'h', 'n', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'n', 'b', 'g', 'h', 'j', 'm', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - 'm', 'n', 'h', 'j', 'k', 'l', 'o', 'p', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, - }; - static { - for (int i = 0; i < PROXIMITY.length; i += ROW_SIZE) { - if (NUL != PROXIMITY[i]) INDICES.put(PROXIMITY[i], i); + 'a', 'z', 'x', 's', 'w', 'q', 'e', 'i', 'o', 'u', NUL, NUL, NUL, NUL, NUL, NUL, + 's', 'q', 'a', 'z', 'x', 'c', 'd', 'e', 'w', NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'd', 'w', 's', 'x', 'c', 'v', 'f', 'r', 'e', 'w', NUL, NUL, NUL, NUL, NUL, NUL, + 'f', 'e', 'd', 'c', 'v', 'b', 'g', 't', 'r', NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'g', 'r', 'f', 'v', 'b', 'n', 'h', 'y', 't', NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'h', 't', 'g', 'b', 'n', 'm', 'j', 'u', 'y', NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'j', 'y', 'h', 'n', 'm', 'k', 'i', 'u', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'k', 'u', 'j', 'm', 'l', 'o', 'i', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'l', 'i', 'k', 'p', 'o', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + + 'z', 'a', 's', 'd', 'x', 't', 'g', 'h', 'j', 'u', 'q', 'e', NUL, NUL, NUL, NUL, + 'x', 'z', 'a', 's', 'd', 'c', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'c', 'x', 's', 'd', 'f', 'v', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'v', 'c', 'd', 'f', 'g', 'b', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'b', 'v', 'f', 'g', 'h', 'n', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'n', 'b', 'g', 'h', 'j', 'm', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'm', 'n', 'h', 'j', 'k', 'l', 'o', 'p', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + }; + static { + buildProximityIndices(PROXIMITY, INDICES); + } + static int getIndexOf(int characterCode) { + return computeIndex(characterCode, INDICES); } } - public static int getIndexOf(int characterCode) { - final Integer result = INDICES.get(characterCode); - if (null == result) return -1; - return result; + + private static class Cyrillic { + final private static TreeMap<Integer, Integer> INDICES = new TreeMap<Integer, Integer>(); + final static int[] PROXIMITY = { + // TODO: This table is solely based on the keyboard layout. Consult with Russian + // speakers on commonly misspelled words/letters. + 'й', 'ц', 'ф', 'ы', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'ц', 'й', 'ф', 'ы', 'в', 'у', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'у', 'ц', 'ы', 'в', 'а', 'к', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'к', 'у', 'в', 'а', 'п', 'е', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'е', 'к', 'а', 'п', 'р', 'н', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'н', 'е', 'п', 'р', 'о', 'г', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'г', 'н', 'р', 'о', 'л', 'ш', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'ш', 'г', 'о', 'л', 'д', 'щ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'щ', 'ш', 'л', 'д', 'ж', 'з', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'з', 'щ', 'д', 'ж', 'э', 'х', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'х', 'з', 'ж', 'э', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + + 'ф', 'й', 'ц', 'ы', 'я', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'ы', 'й', 'ц', 'у', 'ф', 'в', 'я', 'ч', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'в', 'ц', 'у', 'к', 'ы', 'а', 'я', 'ч', 'с', NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'а', 'у', 'к', 'е', 'в', 'п', 'ч', 'с', 'м', NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'п', 'к', 'е', 'н', 'а', 'р', 'с', 'м', 'и', NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'р', 'е', 'н', 'г', 'п', 'о', 'м', 'и', 'т', NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'о', 'н', 'г', 'ш', 'р', 'л', 'и', 'т', 'ь', NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'л', 'г', 'ш', 'щ', 'о', 'д', 'т', 'ь', 'б', NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'д', 'ш', 'щ', 'з', 'л', 'ж', 'ь', 'б', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'ж', 'щ', 'з', 'х', 'д', 'э', 'б', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'э', 'з', 'х', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + + 'я', 'ф', 'ы', 'в', 'ч', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'ч', 'ы', 'в', 'а', 'я', 'с', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'с', 'в', 'а', 'п', 'ч', 'м', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'м', 'а', 'п', 'р', 'с', 'и', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'и', 'п', 'р', 'о', 'м', 'т', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'т', 'р', 'о', 'л', 'и', 'ь', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'ь', 'о', 'л', 'д', 'т', 'б', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'б', 'л', 'д', 'ж', 'ь', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + 'ю', 'д', 'ж', 'э', 'б', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, + }; + static { + buildProximityIndices(PROXIMITY, INDICES); + } + static int getIndexOf(int characterCode) { + return computeIndex(characterCode, INDICES); + } + } + + public static int[] getProximityForScript(final int script) { + switch (script) { + case AndroidSpellCheckerService.SCRIPT_LATIN: + return Latin.PROXIMITY; + case AndroidSpellCheckerService.SCRIPT_CYRILLIC: + return Cyrillic.PROXIMITY; + default: + throw new RuntimeException("Wrong script supplied: " + script); + } + } + public static int getIndexOfCodeForScript(final int characterCode, final int script) { + switch (script) { + case AndroidSpellCheckerService.SCRIPT_LATIN: + return Latin.getIndexOf(characterCode); + case AndroidSpellCheckerService.SCRIPT_CYRILLIC: + return Cyrillic.getIndexOf(characterCode); + default: + throw new RuntimeException("Wrong script supplied: " + script); + } } } diff --git a/java/src/com/android/inputmethod/latin/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java index 9a59ef2e0..4ef5bd386 100644 --- a/java/src/com/android/inputmethod/latin/MoreSuggestions.java +++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java @@ -14,7 +14,7 @@ * the License. */ -package com.android.inputmethod.latin; +package com.android.inputmethod.latin.suggestions; import android.content.res.Resources; import android.graphics.Paint; @@ -25,26 +25,28 @@ import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.KeyboardView; -import com.android.inputmethod.keyboard.internal.KeyboardBuilder; -import com.android.inputmethod.keyboard.internal.KeyboardParams; +import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; +import com.android.inputmethod.latin.LatinImeLogger; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; public class MoreSuggestions extends Keyboard { - private static final boolean DBG = LatinImeLogger.sDBG; - public static final int SUGGESTION_CODE_BASE = 1024; private MoreSuggestions(Builder.MoreSuggestionsParam params) { super(params); } - public static class Builder extends KeyboardBuilder<Builder.MoreSuggestionsParam> { + public static class Builder extends Keyboard.Builder<Builder.MoreSuggestionsParam> { + private static final boolean DBG = LatinImeLogger.sDBG; + private final MoreSuggestionsView mPaneView; private SuggestedWords mSuggestions; private int mFromPos; private int mToPos; - public static class MoreSuggestionsParam extends KeyboardParams { + public static class MoreSuggestionsParam extends Keyboard.Params { private final int[] mWidths = new int[SuggestionsView.MAX_SUGGESTIONS]; private final int[] mRowNumbers = new int[SuggestionsView.MAX_SUGGESTIONS]; private final int[] mColumnOrders = new int[SuggestionsView.MAX_SUGGESTIONS]; @@ -71,7 +73,7 @@ public class MoreSuggestions extends Keyboard { int pos = fromPos, rowStartPos = fromPos; final int size = Math.min(suggestions.size(), SuggestionsView.MAX_SUGGESTIONS); while (pos < size) { - final CharSequence word = suggestions.getWord(pos); + final String word = suggestions.getWord(pos).toString(); // TODO: Should take care of text x-scaling. mWidths[pos] = (int)view.getDefaultLabelWidth(word, paint) + padding; final int numColumn = pos - rowStartPos + 1; @@ -176,9 +178,9 @@ public class MoreSuggestions extends Keyboard { public Builder layout(SuggestedWords suggestions, int fromPos, int maxWidth, int minWidth, int maxRow) { - final Keyboard keyboard = KeyboardSwitcher.getInstance().getLatinKeyboard(); + final Keyboard keyboard = KeyboardSwitcher.getInstance().getKeyboard(); final int xmlId = R.xml.kbd_suggestions_pane_template; - load(keyboard.mId.cloneWithNewXml(mResources.getResourceEntryName(xmlId), xmlId)); + load(xmlId, keyboard.mId); mParams.mVerticalGap = mParams.mTopPadding = keyboard.mVerticalGap / 2; final int count = mParams.layout(suggestions, fromPos, maxWidth, minWidth, maxRow, @@ -198,6 +200,21 @@ public class MoreSuggestions extends Keyboard { return info; } + private static class Divider extends Key.Spacer { + private final Drawable mIcon; + + public Divider(Keyboard.Params params, Drawable icon, int x, int y, int width, + int height) { + super(params, x, y, width, height); + mIcon = icon; + } + + @Override + public Drawable getIcon(KeyboardIconsSet iconSet) { + return mIcon; + } + } + @Override public MoreSuggestions build() { final MoreSuggestionsParam params = mParams; @@ -209,16 +226,16 @@ public class MoreSuggestions extends Keyboard { final String info = getDebugInfo(mSuggestions, pos); final int index = pos + SUGGESTION_CODE_BASE; final Key key = new Key( - params, word, info, null, index, null, x, y, width, - params.mDefaultRowHeight); + params, word, info, KeyboardIconsSet.ICON_UNDEFINED, index, null, x, y, + width, params.mDefaultRowHeight); params.markAsEdgeKey(key, pos); params.onAddKey(key); final int columnNumber = params.getColumnNumber(pos); final int numColumnInRow = params.getNumColumnInRow(pos); if (columnNumber < numColumnInRow - 1) { - final Key.Spacer spacer = new Key.Spacer(params, params.mDivider, x + width, y, + final Divider divider = new Divider(params, params.mDivider, x + width, y, params.mDividerWidth, params.mDefaultRowHeight); - params.onAddKey(spacer); + params.onAddKey(divider); } } return new MoreSuggestions(params); diff --git a/java/src/com/android/inputmethod/latin/MoreSuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java index c61dd6313..cd83c3e21 100644 --- a/java/src/com/android/inputmethod/latin/MoreSuggestionsView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.inputmethod.latin; +package com.android.inputmethod.latin.suggestions; import android.content.Context; import android.content.res.Resources; @@ -34,6 +34,7 @@ import com.android.inputmethod.keyboard.PointerTracker; import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy; import com.android.inputmethod.keyboard.PointerTracker.KeyEventHandler; import com.android.inputmethod.keyboard.PointerTracker.TimerProxy; +import com.android.inputmethod.latin.R; /** * A view that renders a virtual {@link MoreSuggestions}. It handles rendering of keys and detecting @@ -55,13 +56,13 @@ public class MoreSuggestionsView extends KeyboardView implements MoreKeysPanel { private final KeyboardActionListener mSuggestionsPaneListener = new KeyboardActionListener.Adapter() { @Override - public void onPress(int primaryCode, boolean withSliding) { - mListener.onPress(primaryCode, withSliding); + public void onPressKey(int primaryCode) { + mListener.onPressKey(primaryCode); } @Override - public void onRelease(int primaryCode, boolean withSliding) { - mListener.onRelease(primaryCode, withSliding); + public void onReleaseKey(int primaryCode, boolean withSliding) { + mListener.onReleaseKey(primaryCode, withSliding); } @Override @@ -140,11 +141,6 @@ public class MoreSuggestionsView extends KeyboardView implements MoreKeysPanel { } @Override - public void setShifted(boolean shifted) { - // Nothing to do with. - } - - @Override public void showMoreKeysPanel(View parentView, Controller controller, int pointX, int pointY, PopupWindow window, KeyboardActionListener listener) { mController = controller; diff --git a/java/src/com/android/inputmethod/latin/SuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java index c25ecb382..40d782640 100644 --- a/java/src/com/android/inputmethod/latin/SuggestionsView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java @@ -14,7 +14,7 @@ * the License. */ -package com.android.inputmethod.latin; +package com.android.inputmethod.latin.suggestions; import android.content.Context; import android.content.res.Resources; @@ -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; @@ -58,7 +57,12 @@ import com.android.inputmethod.keyboard.KeyboardActionListener; import com.android.inputmethod.keyboard.KeyboardView; import com.android.inputmethod.keyboard.MoreKeysPanel; import com.android.inputmethod.keyboard.PointerTracker; +import com.android.inputmethod.latin.LatinImeLogger; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.StaticInnerHandlerWrapper; +import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.Utils; import java.util.ArrayList; import java.util.List; @@ -73,7 +77,7 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}. public static final int MAX_SUGGESTIONS = 18; - private static final boolean DBG = LatinImeLogger.sDBG; + static final boolean DBG = LatinImeLogger.sDBG; private final ViewGroup mSuggestionsStrip; private KeyboardView mKeyboardView; @@ -101,8 +105,6 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, private static class UiHandler extends StaticInnerHandlerWrapper<SuggestionsView> { private static final int MSG_HIDE_PREVIEW = 0; - private static final long DELAY_HIDE_PREVIEW = 1300; - public UiHandler(SuggestionsView outerInstance) { super(outerInstance); } @@ -117,11 +119,6 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, } } - public void postHidePreview() { - cancelHidePreview(); - sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW); - } - public void cancelHidePreview() { removeMessages(MSG_HIDE_PREVIEW); } @@ -149,6 +146,7 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, private final List<View> mDividers; private final List<TextView> mInfos; + private final int mColorValidTypedWord; private final int mColorTypedWord; private final int mColorAutoCorrect; private final int mColorSuggested; @@ -172,7 +170,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) { @@ -193,6 +190,8 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.SuggestionsView, defStyle, R.style.SuggestionsViewStyle); mSuggestionStripOption = a.getInt(R.styleable.SuggestionsView_suggestionStripOption, 0); + final float alphaValidTypedWord = getPercent(a, + R.styleable.SuggestionsView_alphaValidTypedWord, 100); final float alphaTypedWord = getPercent(a, R.styleable.SuggestionsView_alphaTypedWord, 100); final float alphaAutoCorrect = getPercent(a, @@ -200,6 +199,9 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, final float alphaSuggested = getPercent(a, R.styleable.SuggestionsView_alphaSuggested, 100); mAlphaObsoleted = getPercent(a, R.styleable.SuggestionsView_alphaSuggested, 100); + mColorValidTypedWord = applyAlpha( + a.getColor(R.styleable.SuggestionsView_colorValidTypedWord, 0), + alphaValidTypedWord); mColorTypedWord = applyAlpha( a.getColor(R.styleable.SuggestionsView_colorTypedWord, 0), alphaTypedWord); mColorAutoCorrect = applyAlpha( @@ -228,7 +230,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) { @@ -298,6 +299,8 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, final int color; if (index == mCenterSuggestionIndex && Utils.willAutoCorrect(suggestions)) { color = mColorAutoCorrect; + } else if (index == mCenterSuggestionIndex && suggestions.mTypedWordValid) { + color = mColorValidTypedWord; } else if (isSuggested) { color = mColorSuggested; } else { @@ -433,7 +436,7 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, final TextView word = mWords.get(index); word.setEnabled(true); - word.setTextColor(mColorTypedWord); + word.setTextColor(mColorAutoCorrect); final CharSequence text = suggestions.getWord(index); word.setText(text); word.setTextScaleX(1.0f); @@ -445,7 +448,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,13 +467,98 @@ 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( hintView, 1.0f - mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); } + + private static CharSequence getDebugInfo(SuggestedWords suggestions, int pos) { + if (DBG && pos < suggestions.size()) { + final SuggestedWordInfo wordInfo = suggestions.getInfo(pos); + if (wordInfo != null) { + final CharSequence debugInfo = wordInfo.getDebugString(); + if (!TextUtils.isEmpty(debugInfo)) { + return debugInfo; + } + } + } + return null; + } + + private static void setLayoutWeight(View v, float weight, int height) { + final ViewGroup.LayoutParams lp = v.getLayoutParams(); + if (lp instanceof LinearLayout.LayoutParams) { + final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp; + llp.weight = weight; + llp.width = 0; + llp.height = height; + } + } + + private static float getTextScaleX(CharSequence text, int maxWidth, TextPaint paint) { + paint.setTextScaleX(1.0f); + final int width = getTextWidth(text, paint); + if (width <= maxWidth) { + return 1.0f; + } + return maxWidth / (float)width; + } + + private static CharSequence getEllipsizedText(CharSequence text, int maxWidth, + TextPaint paint) { + if (text == null) return null; + paint.setTextScaleX(1.0f); + final int width = getTextWidth(text, paint); + if (width <= maxWidth) { + return text; + } + final float scaleX = maxWidth / (float)width; + if (scaleX >= MIN_TEXT_XSCALE) { + paint.setTextScaleX(scaleX); + return text; + } + + // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To + // get squeezed and ellipsized text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE). + final CharSequence ellipsized = TextUtils.ellipsize( + text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE); + paint.setTextScaleX(MIN_TEXT_XSCALE); + return ellipsized; + } + + private static int getTextWidth(CharSequence text, TextPaint paint) { + if (TextUtils.isEmpty(text)) return 0; + final Typeface savedTypeface = paint.getTypeface(); + paint.setTypeface(getTextTypeface(text)); + final int len = text.length(); + final float[] widths = new float[len]; + final int count = paint.getTextWidths(text, 0, len, widths); + int width = 0; + for (int i = 0; i < count; i++) { + width += Math.round(widths[i] + 0.5f); + } + paint.setTypeface(savedTypeface); + return width; + } + + private static Typeface getTextTypeface(CharSequence text) { + if (!(text instanceof SpannableString)) + return Typeface.DEFAULT; + + final SpannableString ss = (SpannableString)text; + final StyleSpan[] styles = ss.getSpans(0, text.length(), StyleSpan.class); + if (styles.length == 0) + return Typeface.DEFAULT; + + switch (styles[0].getStyle()) { + case Typeface.BOLD: return Typeface.DEFAULT_BOLD; + // TODO: BOLD_ITALIC, ITALIC case? + default: return Typeface.DEFAULT; + } + } } /** @@ -557,99 +645,15 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, mParams.layout(mSuggestions, mSuggestionsStrip, this, getWidth()); } - private static CharSequence getDebugInfo(SuggestedWords suggestions, int pos) { - if (DBG && pos < suggestions.size()) { - final SuggestedWordInfo wordInfo = suggestions.getInfo(pos); - if (wordInfo != null) { - final CharSequence debugInfo = wordInfo.getDebugString(); - if (!TextUtils.isEmpty(debugInfo)) { - return debugInfo; - } - } - } - return null; - } - - private static void setLayoutWeight(View v, float weight, int height) { - final ViewGroup.LayoutParams lp = v.getLayoutParams(); - if (lp instanceof LinearLayout.LayoutParams) { - final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp; - llp.weight = weight; - llp.width = 0; - llp.height = height; - } - } - - private static float getTextScaleX(CharSequence text, int maxWidth, TextPaint paint) { - paint.setTextScaleX(1.0f); - final int width = getTextWidth(text, paint); - if (width <= maxWidth) { - return 1.0f; - } - return maxWidth / (float)width; - } - - private static CharSequence getEllipsizedText(CharSequence text, int maxWidth, - TextPaint paint) { - if (text == null) return null; - paint.setTextScaleX(1.0f); - final int width = getTextWidth(text, paint); - if (width <= maxWidth) { - return text; - } - final float scaleX = maxWidth / (float)width; - if (scaleX >= MIN_TEXT_XSCALE) { - paint.setTextScaleX(scaleX); - return text; - } - - // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To get - // squeezed and ellipsized text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE). - final CharSequence ellipsized = TextUtils.ellipsize( - text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE); - paint.setTextScaleX(MIN_TEXT_XSCALE); - return ellipsized; - } - - private static int getTextWidth(CharSequence text, TextPaint paint) { - if (TextUtils.isEmpty(text)) return 0; - final Typeface savedTypeface = paint.getTypeface(); - paint.setTypeface(getTextTypeface(text)); - final int len = text.length(); - final float[] widths = new float[len]; - final int count = paint.getTextWidths(text, 0, len, widths); - int width = 0; - for (int i = 0; i < count; i++) { - width += Math.round(widths[i] + 0.5f); - } - paint.setTypeface(savedTypeface); - return width; - } - - private static Typeface getTextTypeface(CharSequence text) { - if (!(text instanceof SpannableString)) - return Typeface.DEFAULT; - - final SpannableString ss = (SpannableString)text; - final StyleSpan[] styles = ss.getSpans(0, text.length(), StyleSpan.class); - if (styles.length == 0) - return Typeface.DEFAULT; - - switch (styles[0].getStyle()) { - case Typeface.BOLD: return Typeface.DEFAULT_BOLD; - // TODO: BOLD_ITALIC, ITALIC case? - default: return Typeface.DEFAULT; - } - } public boolean isShowingAddToDictionaryHint() { return mSuggestionsStrip.getChildCount() > 0 && 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() { @@ -675,34 +679,8 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, mPreviewPopup.dismiss(); } - private void showPreview(View view, CharSequence word) { - if (TextUtils.isEmpty(word)) - return; - - final TextView previewText = mPreviewText; - previewText.setTextColor(mParams.mColorTypedWord); - previewText.setText(word); - previewText.measure( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - final int[] offsetInWindow = new int[2]; - view.getLocationInWindow(offsetInWindow); - final int posX = offsetInWindow[0]; - final int posY = offsetInWindow[1] - previewText.getMeasuredHeight(); - final PopupWindow previewPopup = mPreviewPopup; - if (previewPopup.isShowing()) { - previewPopup.update(posX, posY, previewPopup.getWidth(), previewPopup.getHeight()); - } else { - previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY); - } - previewText.setVisibility(VISIBLE); - mHandler.postHidePreview(); - } - private void addToDictionary(CharSequence word) { - if (mListener.addWordToDictionary(word.toString())) { - final CharSequence message = getContext().getString(R.string.added_word, word); - showPreview(mParams.mWordToSaveView, message); - } + mListener.addWordToDictionary(word.toString()); } private final KeyboardActionListener mMoreSuggestionsListener = @@ -832,8 +810,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/native/Android.mk b/native/Android.mk index cf1da4a41..5053e7d64 100644 --- a/native/Android.mk +++ b/native/Android.mk @@ -1,60 +1 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_C_INCLUDES += $(LOCAL_PATH)/src - -LOCAL_CFLAGS += -Werror -Wall - -# To suppress compiler warnings for unused variables/functions used for debug features etc. -LOCAL_CFLAGS += -Wno-unused-parameter -Wno-unused-function - -LOCAL_SRC_FILES := \ - jni/com_android_inputmethod_keyboard_ProximityInfo.cpp \ - jni/com_android_inputmethod_latin_BinaryDictionary.cpp \ - jni/jni_common.cpp \ - src/bigram_dictionary.cpp \ - src/char_utils.cpp \ - src/correction.cpp \ - src/dictionary.cpp \ - src/proximity_info.cpp \ - src/unigram_dictionary.cpp - -#FLAG_DBG := true -#FLAG_DO_PROFILE := true - -TARGETING_UNBUNDLED_FROYO := true - -ifeq ($(TARGET_ARCH), x86) - TARGETING_UNBUNDLED_FROYO := false -endif - -ifeq ($(FLAG_DBG), true) - TARGETING_UNBUNDLED_FROYO := false -endif - -ifeq ($(FLAG_DO_PROFILE), true) - TARGETING_UNBUNDLED_FROYO := false -endif - -ifeq ($(TARGETING_UNBUNDLED_FROYO), true) - LOCAL_NDK_VERSION := 4 - LOCAL_SDK_VERSION := 8 -endif - -LOCAL_MODULE := libjni_latinime - -LOCAL_MODULE_TAGS := optional - -ifeq ($(FLAG_DO_PROFILE), true) - $(warning Making profiling version of native library) - LOCAL_CFLAGS += -DFLAG_DO_PROFILE - LOCAL_SHARED_LIBRARIES := libcutils libutils -else # FLAG_DO_PROFILE -ifeq ($(FLAG_DBG), true) - $(warning Making debug version of native library) - LOCAL_CFLAGS += -DFLAG_DBG - LOCAL_SHARED_LIBRARIES := libcutils libutils -endif # FLAG_DBG -endif # FLAG_DO_PROFILE - -include $(BUILD_SHARED_LIBRARY) +include $(call all-subdir-makefiles) diff --git a/native/jni/Android.mk b/native/jni/Android.mk new file mode 100644 index 000000000..53bd21ddc --- /dev/null +++ b/native/jni/Android.mk @@ -0,0 +1,87 @@ +# 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. + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LATIN_IME_SRC_DIR := ../src + +LOCAL_C_INCLUDES += $(LOCAL_PATH)/$(LATIN_IME_SRC_DIR) + +LOCAL_CFLAGS += -Werror -Wall + +# To suppress compiler warnings for unused variables/functions used for debug features etc. +LOCAL_CFLAGS += -Wno-unused-parameter -Wno-unused-function + +LATIN_IME_JNI_SRC_FILES := \ + com_android_inputmethod_keyboard_ProximityInfo.cpp \ + com_android_inputmethod_latin_BinaryDictionary.cpp \ + jni_common.cpp + +LATIN_IME_CORE_SRC_FILES := \ + basechars.cpp \ + bigram_dictionary.cpp \ + char_utils.cpp \ + correction.cpp \ + dictionary.cpp \ + proximity_info.cpp \ + unigram_dictionary.cpp + +LOCAL_SRC_FILES := \ + $(LATIN_IME_JNI_SRC_FILES) \ + $(addprefix $(LATIN_IME_SRC_DIR)/,$(LATIN_IME_CORE_SRC_FILES)) + +#FLAG_DBG := true +#FLAG_DO_PROFILE := true + +TARGETING_UNBUNDLED_FROYO := true + +ifeq ($(TARGET_ARCH), x86) + TARGETING_UNBUNDLED_FROYO := false +endif + +ifeq ($(FLAG_DBG), true) + TARGETING_UNBUNDLED_FROYO := false +endif + +ifeq ($(FLAG_DO_PROFILE), true) + TARGETING_UNBUNDLED_FROYO := false +endif + +ifeq ($(TARGETING_UNBUNDLED_FROYO), true) + LOCAL_NDK_VERSION := 4 + LOCAL_SDK_VERSION := 8 +endif + +LOCAL_MODULE := libjni_latinime + +LOCAL_MODULE_TAGS := optional + +# For STL +LOCAL_C_INCLUDES += external/stlport/stlport bionic +LOCAL_SHARED_LIBRARIES += libstlport + +ifeq ($(FLAG_DO_PROFILE), true) + $(warning Making profiling version of native library) + LOCAL_CFLAGS += -DFLAG_DO_PROFILE + LOCAL_SHARED_LIBRARIES += libcutils libutils +else # FLAG_DO_PROFILE +ifeq ($(FLAG_DBG), true) + $(warning Making debug version of native library) + LOCAL_CFLAGS += -DFLAG_DBG + LOCAL_SHARED_LIBRARIES += libcutils libutils +endif # FLAG_DBG +endif # FLAG_DO_PROFILE + +include $(BUILD_SHARED_LIBRARY) diff --git a/native/jni/Application.mk b/native/jni/Application.mk new file mode 100644 index 000000000..caf3b2622 --- /dev/null +++ b/native/jni/Application.mk @@ -0,0 +1 @@ +APP_STL := stlport_static diff --git a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp index 595ea2fdc..6e4fefd72 100644 --- a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp +++ b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp @@ -28,14 +28,14 @@ namespace latinime { -static jint latinime_Keyboard_setProximityInfo(JNIEnv *env, jobject object, +static jlong latinime_Keyboard_setProximityInfo(JNIEnv *env, jobject object, jint maxProximityCharsSize, jint displayWidth, jint displayHeight, jint gridWidth, jint gridHeight, jintArray proximityCharsArray, jint keyCount, jintArray keyXCoordinateArray, jintArray keyYCoordinateArray, jintArray keyWidthArray, jintArray keyHeightArray, jintArray keyCharCodeArray, jfloatArray sweetSpotCenterXArray, jfloatArray sweetSpotCenterYArray, jfloatArray sweetSpotRadiusArray) { - jint *proximityChars = env->GetIntArrayElements(proximityCharsArray, NULL); + jint *proximityChars = env->GetIntArrayElements(proximityCharsArray, 0); jint *keyXCoordinates = safeGetIntArrayElements(env, keyXCoordinateArray); jint *keyYCoordinates = safeGetIntArrayElements(env, keyYCoordinateArray); jint *keyWidths = safeGetIntArrayElements(env, keyWidthArray); @@ -59,19 +59,19 @@ static jint latinime_Keyboard_setProximityInfo(JNIEnv *env, jobject object, safeReleaseIntArrayElements(env, keyYCoordinateArray, keyYCoordinates); safeReleaseIntArrayElements(env, keyXCoordinateArray, keyXCoordinates); env->ReleaseIntArrayElements(proximityCharsArray, proximityChars, 0); - return (jint)proximityInfo; + return (jlong)proximityInfo; } -static void latinime_Keyboard_release(JNIEnv *env, jobject object, jint proximityInfo) { +static void latinime_Keyboard_release(JNIEnv *env, jobject object, jlong proximityInfo) { ProximityInfo *pi = (ProximityInfo*)proximityInfo; if (!pi) return; delete pi; } static JNINativeMethod sKeyboardMethods[] = { - {"setProximityInfoNative", "(IIIII[II[I[I[I[I[I[F[F[F)I", + {"setProximityInfoNative", "(IIIII[II[I[I[I[I[I[F[F[F)J", (void*)latinime_Keyboard_setProximityInfo}, - {"releaseProximityInfoNative", "(I)V", (void*)latinime_Keyboard_release} + {"releaseProximityInfoNative", "(J)V", (void*)latinime_Keyboard_release} }; int register_ProximityInfo(JNIEnv *env) { diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index 18c972444..f2878eea5 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -18,6 +18,7 @@ #define LOG_TAG "LatinIME: jni: BinaryDictionary" #include "binary_format.h" +#include "correction.h" #include "com_android_inputmethod_latin_BinaryDictionary.h" #include "dictionary.h" #include "jni.h" @@ -33,6 +34,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> +#include <unistd.h> #else // USE_MMAP_FOR_DICTIONARY #include <stdlib.h> #endif // USE_MMAP_FOR_DICTIONARY @@ -41,75 +43,75 @@ namespace latinime { void releaseDictBuf(void* dictBuf, const size_t length, int fd); -static jint latinime_BinaryDictionary_open(JNIEnv *env, jobject object, +static jlong latinime_BinaryDictionary_open(JNIEnv *env, jobject object, jstring sourceDir, jlong dictOffset, jlong dictSize, jint typedLetterMultiplier, jint fullWordMultiplier, jint maxWordLength, jint maxWords, jint maxAlternatives) { PROF_OPEN; PROF_START(66); - const char *sourceDirChars = env->GetStringUTFChars(sourceDir, NULL); - if (sourceDirChars == NULL) { - LOGE("DICT: Can't get sourceDir string"); + const char *sourceDirChars = env->GetStringUTFChars(sourceDir, 0); + if (sourceDirChars == 0) { + AKLOGE("DICT: Can't get sourceDir string"); return 0; } int fd = 0; - void *dictBuf = NULL; + void *dictBuf = 0; int adjust = 0; #ifdef USE_MMAP_FOR_DICTIONARY /* mmap version */ fd = open(sourceDirChars, O_RDONLY); if (fd < 0) { - LOGE("DICT: Can't open sourceDir. sourceDirChars=%s errno=%d", sourceDirChars, errno); + AKLOGE("DICT: Can't open sourceDir. sourceDirChars=%s errno=%d", sourceDirChars, errno); return 0; } int pagesize = getpagesize(); adjust = dictOffset % pagesize; int adjDictOffset = dictOffset - adjust; int adjDictSize = dictSize + adjust; - dictBuf = mmap(NULL, sizeof(char) * adjDictSize, PROT_READ, MAP_PRIVATE, fd, adjDictOffset); + dictBuf = mmap(0, sizeof(char) * adjDictSize, PROT_READ, MAP_PRIVATE, fd, adjDictOffset); if (dictBuf == MAP_FAILED) { - LOGE("DICT: Can't mmap dictionary. errno=%d", errno); + AKLOGE("DICT: Can't mmap dictionary. errno=%d", errno); return 0; } dictBuf = (void *)((char *)dictBuf + adjust); #else // USE_MMAP_FOR_DICTIONARY /* malloc version */ - FILE *file = NULL; + FILE *file = 0; file = fopen(sourceDirChars, "rb"); - if (file == NULL) { - LOGE("DICT: Can't fopen sourceDir. sourceDirChars=%s errno=%d", sourceDirChars, errno); + if (file == 0) { + AKLOGE("DICT: Can't fopen sourceDir. sourceDirChars=%s errno=%d", sourceDirChars, errno); return 0; } dictBuf = malloc(sizeof(char) * dictSize); if (!dictBuf) { - LOGE("DICT: Can't allocate memory region for dictionary. errno=%d", errno); + AKLOGE("DICT: Can't allocate memory region for dictionary. errno=%d", errno); return 0; } int ret = fseek(file, (long)dictOffset, SEEK_SET); if (ret != 0) { - LOGE("DICT: Failure in fseek. ret=%d errno=%d", ret, errno); + AKLOGE("DICT: Failure in fseek. ret=%d errno=%d", ret, errno); return 0; } ret = fread(dictBuf, sizeof(char) * dictSize, 1, file); if (ret != 1) { - LOGE("DICT: Failure in fread. ret=%d errno=%d", ret, errno); + AKLOGE("DICT: Failure in fread. ret=%d errno=%d", ret, errno); return 0; } ret = fclose(file); if (ret != 0) { - LOGE("DICT: Failure in fclose. ret=%d errno=%d", ret, errno); + AKLOGE("DICT: Failure in fclose. ret=%d errno=%d", ret, errno); return 0; } #endif // USE_MMAP_FOR_DICTIONARY env->ReleaseStringUTFChars(sourceDir, sourceDirChars); if (!dictBuf) { - LOGE("DICT: dictBuf is null"); + AKLOGE("DICT: dictBuf is null"); return 0; } - Dictionary *dictionary = NULL; + Dictionary *dictionary = 0; if (BinaryFormat::UNKNOWN_FORMAT == BinaryFormat::detectFormat((uint8_t*)dictBuf)) { - LOGE("DICT: dictionary format is unknown, bad magic number"); + AKLOGE("DICT: dictionary format is unknown, bad magic number"); #ifdef USE_MMAP_FOR_DICTIONARY releaseDictBuf(((char*)dictBuf) - adjust, adjDictSize, fd); #else // USE_MMAP_FOR_DICTIONARY @@ -121,23 +123,23 @@ static jint latinime_BinaryDictionary_open(JNIEnv *env, jobject object, } PROF_END(66); PROF_CLOSE; - return (jint)dictionary; + return (jlong)dictionary; } -static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, jint dict, - jint proximityInfo, jintArray xCoordinatesArray, jintArray yCoordinatesArray, +static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, jlong dict, + jlong proximityInfo, jintArray xCoordinatesArray, jintArray yCoordinatesArray, jintArray inputArray, jint arraySize, jint flags, jcharArray outputArray, jintArray frequencyArray) { Dictionary *dictionary = (Dictionary*)dict; if (!dictionary) return 0; ProximityInfo *pInfo = (ProximityInfo*)proximityInfo; - int *xCoordinates = env->GetIntArrayElements(xCoordinatesArray, NULL); - int *yCoordinates = env->GetIntArrayElements(yCoordinatesArray, NULL); + int *xCoordinates = env->GetIntArrayElements(xCoordinatesArray, 0); + int *yCoordinates = env->GetIntArrayElements(yCoordinatesArray, 0); - int *frequencies = env->GetIntArrayElements(frequencyArray, NULL); - int *inputCodes = env->GetIntArrayElements(inputArray, NULL); - jchar *outputChars = env->GetCharArrayElements(outputArray, NULL); + int *frequencies = env->GetIntArrayElements(frequencyArray, 0); + int *inputCodes = env->GetIntArrayElements(inputArray, 0); + jchar *outputChars = env->GetCharArrayElements(outputArray, 0); int count = dictionary->getSuggestions(pInfo, xCoordinates, yCoordinates, inputCodes, arraySize, flags, (unsigned short*) outputChars, frequencies); @@ -151,17 +153,17 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, return count; } -static int latinime_BinaryDictionary_getBigrams(JNIEnv *env, jobject object, jint dict, +static int latinime_BinaryDictionary_getBigrams(JNIEnv *env, jobject object, jlong dict, jcharArray prevWordArray, jint prevWordLength, jintArray inputArray, jint inputArraySize, jcharArray outputArray, jintArray frequencyArray, jint maxWordLength, jint maxBigrams, jint maxAlternatives) { Dictionary *dictionary = (Dictionary*)dict; if (!dictionary) return 0; - jchar *prevWord = env->GetCharArrayElements(prevWordArray, NULL); - int *inputCodes = env->GetIntArrayElements(inputArray, NULL); - jchar *outputChars = env->GetCharArrayElements(outputArray, NULL); - int *frequencies = env->GetIntArrayElements(frequencyArray, NULL); + jchar *prevWord = env->GetCharArrayElements(prevWordArray, 0); + int *inputCodes = env->GetIntArrayElements(inputArray, 0); + jchar *outputChars = env->GetCharArrayElements(outputArray, 0); + int *frequencies = env->GetIntArrayElements(frequencyArray, 0); int count = dictionary->getBigrams((unsigned short*) prevWord, prevWordLength, inputCodes, inputArraySize, (unsigned short*) outputChars, frequencies, maxWordLength, maxBigrams, @@ -175,19 +177,42 @@ static int latinime_BinaryDictionary_getBigrams(JNIEnv *env, jobject object, jin return count; } -static jboolean latinime_BinaryDictionary_isValidWord(JNIEnv *env, jobject object, jint dict, +static jboolean latinime_BinaryDictionary_isValidWord(JNIEnv *env, jobject object, jlong dict, jcharArray wordArray, jint wordLength) { Dictionary *dictionary = (Dictionary*)dict; if (!dictionary) return (jboolean) false; - jchar *word = env->GetCharArrayElements(wordArray, NULL); + jchar *word = env->GetCharArrayElements(wordArray, 0); jboolean result = dictionary->isValidWord((unsigned short*) word, wordLength); env->ReleaseCharArrayElements(wordArray, word, JNI_ABORT); return result; } -static void latinime_BinaryDictionary_close(JNIEnv *env, jobject object, jint dict) { +static jdouble latinime_BinaryDictionary_calcNormalizedScore(JNIEnv *env, jobject object, + jcharArray before, jint beforeLength, jcharArray after, jint afterLength, jint score) { + jchar *beforeChars = env->GetCharArrayElements(before, 0); + jchar *afterChars = env->GetCharArrayElements(after, 0); + jdouble result = Correction::RankingAlgorithm::calcNormalizedScore( + (unsigned short*)beforeChars, beforeLength, (unsigned short*)afterChars, afterLength, + score); + env->ReleaseCharArrayElements(before, beforeChars, JNI_ABORT); + env->ReleaseCharArrayElements(after, afterChars, JNI_ABORT); + return result; +} + +static jint latinime_BinaryDictionary_editDistance(JNIEnv *env, jobject object, + jcharArray before, jint beforeLength, jcharArray after, jint afterLength) { + jchar *beforeChars = env->GetCharArrayElements(before, 0); + jchar *afterChars = env->GetCharArrayElements(after, 0); + jint result = Correction::RankingAlgorithm::editDistance( + (unsigned short*)beforeChars, beforeLength, (unsigned short*)afterChars, afterLength); + env->ReleaseCharArrayElements(before, beforeChars, JNI_ABORT); + env->ReleaseCharArrayElements(after, afterChars, JNI_ABORT); + return result; +} + +static void latinime_BinaryDictionary_close(JNIEnv *env, jobject object, jlong dict) { Dictionary *dictionary = (Dictionary*)dict; if (!dictionary) return; void *dictBuf = dictionary->getDict(); @@ -205,11 +230,11 @@ void releaseDictBuf(void* dictBuf, const size_t length, int fd) { #ifdef USE_MMAP_FOR_DICTIONARY int ret = munmap(dictBuf, length); if (ret != 0) { - LOGE("DICT: Failure in munmap. ret=%d errno=%d", ret, errno); + AKLOGE("DICT: Failure in munmap. ret=%d errno=%d", ret, errno); } ret = close(fd); if (ret != 0) { - LOGE("DICT: Failure in close. ret=%d errno=%d", ret, errno); + AKLOGE("DICT: Failure in close. ret=%d errno=%d", ret, errno); } #else // USE_MMAP_FOR_DICTIONARY free(dictBuf); @@ -217,11 +242,14 @@ void releaseDictBuf(void* dictBuf, const size_t length, int fd) { } static JNINativeMethod sMethods[] = { - {"openNative", "(Ljava/lang/String;JJIIIII)I", (void*)latinime_BinaryDictionary_open}, - {"closeNative", "(I)V", (void*)latinime_BinaryDictionary_close}, - {"getSuggestionsNative", "(II[I[I[III[C[I)I", (void*)latinime_BinaryDictionary_getSuggestions}, - {"isValidWordNative", "(I[CI)Z", (void*)latinime_BinaryDictionary_isValidWord}, - {"getBigramsNative", "(I[CI[II[C[IIII)I", (void*)latinime_BinaryDictionary_getBigrams} + {"openNative", "(Ljava/lang/String;JJIIIII)J", (void*)latinime_BinaryDictionary_open}, + {"closeNative", "(J)V", (void*)latinime_BinaryDictionary_close}, + {"getSuggestionsNative", "(JJ[I[I[III[C[I)I", (void*)latinime_BinaryDictionary_getSuggestions}, + {"isValidWordNative", "(J[CI)Z", (void*)latinime_BinaryDictionary_isValidWord}, + {"getBigramsNative", "(J[CI[II[C[IIII)I", (void*)latinime_BinaryDictionary_getBigrams}, + {"calcNormalizedScoreNative", "([CI[CII)D", + (void*)latinime_BinaryDictionary_calcNormalizedScore}, + {"editDistanceNative", "([CI[CI)I", (void*)latinime_BinaryDictionary_editDistance} }; int register_BinaryDictionary(JNIEnv *env) { diff --git a/native/jni/jni_common.cpp b/native/jni/jni_common.cpp index 8643f723f..85d26836a 100644 --- a/native/jni/jni_common.cpp +++ b/native/jni/jni_common.cpp @@ -32,22 +32,22 @@ using namespace latinime; * Returns the JNI version on success, -1 on failure. */ jint JNI_OnLoad(JavaVM* vm, void* reserved) { - JNIEnv* env = NULL; + JNIEnv* env = 0; jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { - LOGE("ERROR: GetEnv failed"); + AKLOGE("ERROR: GetEnv failed"); goto bail; } - assert(env != NULL); + assert(env != 0); if (!register_BinaryDictionary(env)) { - LOGE("ERROR: BinaryDictionary native registration failed"); + AKLOGE("ERROR: BinaryDictionary native registration failed"); goto bail; } if (!register_ProximityInfo(env)) { - LOGE("ERROR: ProximityInfo native registration failed"); + AKLOGE("ERROR: ProximityInfo native registration failed"); goto bail; } @@ -63,12 +63,12 @@ namespace latinime { int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* methods, int numMethods) { jclass clazz = env->FindClass(className); - if (clazz == NULL) { - LOGE("Native registration unable to find class '%s'", className); + if (clazz == 0) { + AKLOGE("Native registration unable to find class '%s'", className); return JNI_FALSE; } if (env->RegisterNatives(clazz, methods, numMethods) < 0) { - LOGE("RegisterNatives failed for '%s'", className); + AKLOGE("RegisterNatives failed for '%s'", className); env->DeleteLocalRef(clazz); return JNI_FALSE; } diff --git a/native/jni/jni_common.h b/native/jni/jni_common.h index 9548e1b3f..6741443ac 100644 --- a/native/jni/jni_common.h +++ b/native/jni/jni_common.h @@ -29,17 +29,17 @@ int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *m inline jint *safeGetIntArrayElements(JNIEnv *env, jintArray jArray) { if (jArray) { - return env->GetIntArrayElements(jArray, NULL); + return env->GetIntArrayElements(jArray, 0); } else { - return NULL; + return 0; } } inline jfloat *safeGetFloatArrayElements(JNIEnv *env, jfloatArray jArray) { if (jArray) { - return env->GetFloatArrayElements(jArray, NULL); + return env->GetFloatArrayElements(jArray, 0); } else { - return NULL; + return 0; } } diff --git a/native/src/basechars.h b/native/src/basechars.cpp index 3843e11c5..31f1e18a8 100644 --- a/native/src/basechars.h +++ b/native/src/basechars.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * 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. @@ -14,8 +14,9 @@ * limitations under the License. */ -#ifndef LATINIME_BASECHARS_H -#define LATINIME_BASECHARS_H +#include "char_utils.h" + +namespace latinime { /** * Table mapping most combined Latin, Greek, and Cyrillic characters @@ -23,7 +24,7 @@ * if c is not a combined character, or the base character if it * is combined. */ -static unsigned short BASE_CHARS[] = { +const unsigned short BASE_CHARS[BASE_CHARS_SIZE] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, @@ -189,4 +190,5 @@ static unsigned short BASE_CHARS[] = { // generated with: // cat UnicodeData.txt | perl -e 'while (<>) { @foo = split(/;/); $foo[5] =~ s/<.*> //; $base[hex($foo[0])] = hex($foo[5]);} for ($i = 0; $i < 0x500; $i += 8) { for ($j = $i; $j < $i + 8; $j++) { printf("0x%04x, ", $base[$j] ? $base[$j] : $j)}; print "\n"; }' -#endif // LATINIME_BASECHARS_H + +} // namespace latinime diff --git a/native/src/bigram_dictionary.cpp b/native/src/bigram_dictionary.cpp index c340c6c1a..db7734bc7 100644 --- a/native/src/bigram_dictionary.cpp +++ b/native/src/bigram_dictionary.cpp @@ -32,8 +32,8 @@ BigramDictionary::BigramDictionary(const unsigned char *dict, int maxWordLength, MAX_ALTERNATIVES(maxAlternatives), IS_LATEST_DICT_VERSION(isLatestDictVersion), HAS_BIGRAM(hasBigram), mParentDictionary(parentDictionary) { if (DEBUG_DICT) { - LOGI("BigramDictionary - constructor"); - LOGI("Has Bigram : %d", hasBigram); + AKLOGI("BigramDictionary - constructor"); + AKLOGI("Has Bigram : %d", hasBigram); } } @@ -46,7 +46,7 @@ bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequ #ifdef FLAG_DBG char s[length + 1]; for (int i = 0; i <= length; i++) s[i] = word[i]; - LOGI("Bigram: Found word = %s, freq = %d :", s, frequency); + AKLOGI("Bigram: Found word = %s, freq = %d :", s, frequency); #endif } @@ -60,7 +60,7 @@ bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequ insertAt++; } if (DEBUG_DICT) { - LOGI("Bigram: InsertAt -> %d maxBigrams: %d", insertAt, mMaxBigrams); + AKLOGI("Bigram: InsertAt -> %d maxBigrams: %d", insertAt, mMaxBigrams); } if (insertAt < mMaxBigrams) { memmove((char*) mBigramFreq + (insertAt + 1) * sizeof(mBigramFreq[0]), @@ -76,7 +76,7 @@ bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequ } *dest = 0; // NULL terminate if (DEBUG_DICT) { - LOGI("Bigram: Added word at %d", insertAt); + AKLOGI("Bigram: Added word at %d", insertAt); } return true; } diff --git a/native/src/bigram_dictionary.h b/native/src/bigram_dictionary.h index c07458a38..585a1866a 100644 --- a/native/src/bigram_dictionary.h +++ b/native/src/bigram_dictionary.h @@ -21,14 +21,14 @@ namespace latinime { class Dictionary; class BigramDictionary { -public: + public: BigramDictionary(const unsigned char *dict, int maxWordLength, int maxAlternatives, const bool isLatestDictVersion, const bool hasBigram, Dictionary *parentDictionary); int getBigrams(unsigned short *word, int length, int *codes, int codesSize, unsigned short *outWords, int *frequencies, int maxWordLength, int maxBigrams, int maxAlternatives); ~BigramDictionary(); -private: + private: bool addWordBigram(unsigned short *word, int length, int frequency); int getBigramAddress(int *pos, bool advance); int getBigramFreq(int *pos); diff --git a/native/src/binary_format.h b/native/src/binary_format.h index 6f65088db..1d74998f6 100644 --- a/native/src/binary_format.h +++ b/native/src/binary_format.h @@ -22,12 +22,12 @@ namespace latinime { class BinaryFormat { -private: + private: const static int32_t MINIMAL_ONE_BYTE_CHARACTER_VALUE = 0x20; const static int32_t CHARACTER_ARRAY_TERMINATOR = 0x1F; const static int MULTIPLE_BYTE_CHARACTER_ADDITIONAL_SIZE = 2; -public: + public: const static int UNKNOWN_FORMAT = -1; const static int FORMAT_VERSION_1 = 1; const static uint16_t FORMAT_VERSION_1_MAGIC_NUMBER = 0x78B1; @@ -61,7 +61,9 @@ inline int BinaryFormat::detectFormat(const uint8_t* const dict) { } inline int BinaryFormat::getGroupCountAndForwardPointer(const uint8_t* const dict, int* pos) { - return dict[(*pos)++]; + const int msb = dict[(*pos)++]; + if (msb < 0x80) return msb; + return ((msb & 0x7F) << 8) | dict[(*pos)++]; } inline uint8_t BinaryFormat::getFlagsAndForwardPointer(const uint8_t* const dict, int* pos) { @@ -145,15 +147,15 @@ inline int BinaryFormat::skipFrequency(const uint8_t flags, const int pos) { inline int BinaryFormat::skipAllAttributes(const uint8_t* const dict, const uint8_t flags, const int pos) { - // This function skips all attributes. The format makes provision for future extension - // with other attributes (notably shortcuts) but for the time being, bigrams are the - // only attributes that may be found in a character group, so we only look at bigrams - // in this version. + // This function skips all attributes: shortcuts and bigrams. + int newPos = pos; + if (UnigramDictionary::FLAG_HAS_SHORTCUT_TARGETS & flags) { + newPos = skipAttributes(dict, newPos); + } if (UnigramDictionary::FLAG_HAS_BIGRAMS & flags) { - return skipAttributes(dict, pos); - } else { - return pos; + newPos = skipAttributes(dict, newPos); } + return newPos; } inline int BinaryFormat::skipChildrenPosAndAttributes(const uint8_t* const dict, diff --git a/native/src/char_utils.h b/native/src/char_utils.h index a69a35e7a..607dc5195 100644 --- a/native/src/char_utils.h +++ b/native/src/char_utils.h @@ -19,8 +19,47 @@ namespace latinime { +inline static int isAsciiUpper(unsigned short c) { + return c >= 'A' && c <= 'Z'; +} + +inline static unsigned short toAsciiLower(unsigned short c) { + return c - 'A' + 'a'; +} + +inline static int isAscii(unsigned short c) { + return c <= 127; +} + unsigned short latin_tolower(unsigned short c); +/** + * Table mapping most combined Latin, Greek, and Cyrillic characters + * to their base characters. If c is in range, BASE_CHARS[c] == c + * if c is not a combined character, or the base character if it + * is combined. + */ + +static const int BASE_CHARS_SIZE = 0x0500; +extern const unsigned short BASE_CHARS[BASE_CHARS_SIZE]; + +inline static unsigned short toBaseChar(unsigned short c) { + if (c < BASE_CHARS_SIZE) { + return BASE_CHARS[c]; + } + return c; +} + +inline static unsigned short toBaseLowerCase(unsigned short c) { + c = toBaseChar(c); + if (isAsciiUpper(c)) { + return toAsciiLower(c); + } else if (isAscii(c)) { + return c; + } + return latin_tolower(c); +} + } // namespace latinime #endif // LATINIME_CHAR_UTILS_H diff --git a/native/src/correction.cpp b/native/src/correction.cpp index 27dc40745..087219ed4 100644 --- a/native/src/correction.cpp +++ b/native/src/correction.cpp @@ -16,12 +16,15 @@ #include <assert.h> #include <ctype.h> +#include <math.h> #include <stdio.h> #include <string.h> #define LOG_TAG "LatinIME: correction.cpp" +#include "char_utils.h" #include "correction.h" +#include "defines.h" #include "dictionary.h" #include "proximity_info.h" @@ -31,81 +34,60 @@ namespace latinime { // edit distance funcitons // ///////////////////////////// -#if 0 /* no longer used */ -inline static int editDistance( - int* editDistanceTable, const unsigned short* input, - const int inputLength, const unsigned short* output, const int outputLength) { - // dp[li][lo] dp[a][b] = dp[ a * lo + b] - int* dp = editDistanceTable; - const int li = inputLength + 1; - const int lo = outputLength + 1; - for (int i = 0; i < li; ++i) { - dp[lo * i] = i; - } - for (int i = 0; i < lo; ++i) { - dp[i] = i; - } - - for (int i = 0; i < li - 1; ++i) { - for (int j = 0; j < lo - 1; ++j) { - const uint32_t ci = Dictionary::toBaseLowerCase(input[i]); - const uint32_t co = Dictionary::toBaseLowerCase(output[j]); - const uint16_t cost = (ci == co) ? 0 : 1; - dp[(i + 1) * lo + (j + 1)] = min(dp[i * lo + (j + 1)] + 1, - min(dp[(i + 1) * lo + j] + 1, dp[i * lo + j] + cost)); - if (i > 0 && j > 0 && ci == Dictionary::toBaseLowerCase(output[j - 1]) - && co == Dictionary::toBaseLowerCase(input[i - 1])) { - dp[(i + 1) * lo + (j + 1)] = min( - dp[(i + 1) * lo + (j + 1)], dp[(i - 1) * lo + (j - 1)] + cost); - } - } +inline static void initEditDistance(int *editDistanceTable) { + for (int i = 0; i <= MAX_WORD_LENGTH_INTERNAL; ++i) { + editDistanceTable[i] = i; } +} - if (DEBUG_EDIT_DISTANCE) { - LOGI("IN = %d, OUT = %d", inputLength, outputLength); - for (int i = 0; i < li; ++i) { - for (int j = 0; j < lo; ++j) { - LOGI("EDIT[%d][%d], %d", i, j, dp[i * lo + j]); +inline static void dumpEditDistance10ForDebug(int *editDistanceTable, + const int editDistanceTableWidth, const int outputLength) { + if (DEBUG_DICT) { + AKLOGI("EditDistanceTable"); + for (int i = 0; i <= 10; ++i) { + int c[11]; + for (int j = 0; j <= 10; ++j) { + if (j < editDistanceTableWidth + 1 && i < outputLength + 1) { + c[j] = (editDistanceTable + i * (editDistanceTableWidth + 1))[j]; + } else { + c[j] = -1; + } } + AKLOGI("[ %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d ]", + c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10]); } } - return dp[li * lo - 1]; -} -#endif - -inline static void initEditDistance(int *editDistanceTable) { - for (int i = 0; i <= MAX_WORD_LENGTH_INTERNAL; ++i) { - editDistanceTable[i] = i; - } } inline static void calcEditDistanceOneStep(int *editDistanceTable, const unsigned short *input, const int inputLength, const unsigned short *output, const int outputLength) { + // TODO: Make sure that editDistance[0 ~ MAX_WORD_LENGTH_INTERNAL] is not touched. // Let dp[i][j] be editDistanceTable[i * (inputLength + 1) + j]. // Assuming that dp[0][0] ... dp[outputLength - 1][inputLength] are already calculated, // and calculate dp[ouputLength][0] ... dp[outputLength][inputLength]. int *const current = editDistanceTable + outputLength * (inputLength + 1); const int *const prev = editDistanceTable + (outputLength - 1) * (inputLength + 1); const int *const prevprev = - outputLength >= 2 ? editDistanceTable + (outputLength - 2) * (inputLength + 1) : NULL; + outputLength >= 2 ? editDistanceTable + (outputLength - 2) * (inputLength + 1) : 0; current[0] = outputLength; - const uint32_t co = Dictionary::toBaseLowerCase(output[outputLength - 1]); - const uint32_t prevCO = - outputLength >= 2 ? Dictionary::toBaseLowerCase(output[outputLength - 2]) : 0; + const uint32_t co = toBaseLowerCase(output[outputLength - 1]); + const uint32_t prevCO = outputLength >= 2 ? toBaseLowerCase(output[outputLength - 2]) : 0; for (int i = 1; i <= inputLength; ++i) { - const uint32_t ci = Dictionary::toBaseLowerCase(input[i - 1]); + const uint32_t ci = toBaseLowerCase(input[i - 1]); const uint16_t cost = (ci == co) ? 0 : 1; current[i] = min(current[i - 1] + 1, min(prev[i] + 1, prev[i - 1] + cost)); - if (i >= 2 && prevprev && ci == prevCO - && co == Dictionary::toBaseLowerCase(input[i - 2])) { + if (i >= 2 && prevprev && ci == prevCO && co == toBaseLowerCase(input[i - 2])) { current[i] = min(current[i], prevprev[i - 2] + 1); } } } -inline static int getCurrentEditDistance( - int *editDistanceTable, const int inputLength, const int outputLength) { - return editDistanceTable[(inputLength + 1) * (outputLength + 1) - 1]; +inline static int getCurrentEditDistance(int *editDistanceTable, const int editDistanceTableWidth, + const int outputLength, const int inputLength) { + if (DEBUG_EDIT_DISTANCE) { + AKLOGI("getCurrentEditDistance %d, %d", inputLength, outputLength); + } + return editDistanceTable[(editDistanceTableWidth + 1) * (outputLength) + inputLength]; } ////////////////////// @@ -133,6 +115,9 @@ void Correction::initCorrection(const ProximityInfo *pi, const int inputLength, mInputLength = inputLength; mMaxDepth = maxDepth; mMaxEditDistance = mInputLength < 5 ? 2 : mInputLength / 2; + // TODO: This is not supposed to be required. Check what's going wrong with + // editDistance[0 ~ MAX_WORD_LENGTH_INTERNAL] + initEditDistance(mEditDistanceTable); } void Correction::initCorrectionState( @@ -146,7 +131,7 @@ void Correction::initCorrectionState( void Correction::setCorrectionParams(const int skipPos, const int excessivePos, const int transposedPos, const int spaceProximityPos, const int missingSpacePos, - const bool useFullEditDistance) { + const bool useFullEditDistance, const bool doAutoCompletion, const int maxErrors) { // TODO: remove mTransposedPos = transposedPos; mExcessivePos = excessivePos; @@ -159,6 +144,8 @@ void Correction::setCorrectionParams(const int skipPos, const int excessivePos, mSpaceProximityPos = spaceProximityPos; mMissingSpacePos = missingSpacePos; mUseFullEditDistance = useFullEditDistance; + mDoAutoCompletion = doAutoCompletion; + mMaxErrors = maxErrors; } void Correction::checkState() { @@ -172,23 +159,34 @@ void Correction::checkState() { } } -int Correction::getFreqForSplitTwoWords(const int firstFreq, const int secondFreq, - const unsigned short *word) { - return Correction::RankingAlgorithm::calcFreqForSplitTwoWords( - firstFreq, secondFreq, this, word); +int Correction::getFreqForSplitMultipleWords(const int *freqArray, const int *wordLengthArray, + const int wordCount, const bool isSpaceProximity, const unsigned short *word) { + return Correction::RankingAlgorithm::calcFreqForSplitMultipleWords(freqArray, wordLengthArray, + wordCount, this, isSpaceProximity, word); } int Correction::getFinalFreq(const int freq, unsigned short **word, int *wordLength) { + return getFinalFreqInternal(freq, word, wordLength, mInputLength); +} + +int Correction::getFinalFreqForSubQueue(const int freq, unsigned short **word, int *wordLength, + const int inputLength) { + return getFinalFreqInternal(freq, word, wordLength, inputLength); +} + +int Correction::getFinalFreqInternal(const int freq, unsigned short **word, int *wordLength, + const int inputLength) { const int outputIndex = mTerminalOutputIndex; const int inputIndex = mTerminalInputIndex; *wordLength = outputIndex + 1; - if (mProximityInfo->sameAsTyped(mWord, outputIndex + 1) || outputIndex < MIN_SUGGEST_DEPTH) { - return -1; + if (outputIndex < MIN_SUGGEST_DEPTH) { + return NOT_A_FREQUENCY; } *word = mWord; - return Correction::RankingAlgorithm::calculateFinalFreq( - inputIndex, outputIndex, freq, mEditDistanceTable, this); + int finalFreq = Correction::RankingAlgorithm::calculateFinalFreq( + inputIndex, outputIndex, freq, mEditDistanceTable, this, inputLength); + return finalFreq; } bool Correction::initProcessState(const int outputIndex) { @@ -213,6 +211,7 @@ bool Correction::initProcessState(const int outputIndex) { mMatching = false; mProximityMatching = false; + mAdditionalProximityMatching = false; mTransposing = false; mExceeding = false; mSkipping = false; @@ -229,20 +228,10 @@ int Correction::goDownTree( } // TODO: remove -int Correction::getOutputIndex() { - return mOutputIndex; -} - -// TODO: remove int Correction::getInputIndex() { return mInputIndex; } -// TODO: remove -bool Correction::needsToTraverseAllNodes() { - return mNeedsToTraverseAllNodes; -} - void Correction::incrementInputIndex() { ++mInputIndex; } @@ -269,6 +258,7 @@ void Correction::incrementOutputIndex() { mCorrectionStates[mOutputIndex].mMatching = mMatching; mCorrectionStates[mOutputIndex].mProximityMatching = mProximityMatching; + mCorrectionStates[mOutputIndex].mAdditionalProximityMatching = mAdditionalProximityMatching; mCorrectionStates[mOutputIndex].mTransposing = mTransposing; mCorrectionStates[mOutputIndex].mExceeding = mExceeding; mCorrectionStates[mOutputIndex].mSkipping = mSkipping; @@ -280,7 +270,9 @@ void Correction::startToTraverseAllNodes() { bool Correction::needsToPrune() const { // TODO: use edit distance here - return mOutputIndex - 1 >= mMaxDepth || mProximityCount > mMaxEditDistance; + return mOutputIndex - 1 >= mMaxDepth || mProximityCount > mMaxEditDistance + // Allow one char longer word for missing character + || (!mDoAutoCompletion && (mOutputIndex > mInputLength)); } void Correction::addCharToCurrentWord(const int32_t c) { @@ -290,13 +282,12 @@ void Correction::addCharToCurrentWord(const int32_t c) { mWord, mOutputIndex + 1); } -// TODO: inline? Correction::CorrectionType Correction::processSkipChar( const int32_t c, const bool isTerminal, const bool inputIndexIncremented) { addCharToCurrentWord(c); - if (needsToTraverseAllNodes() && isTerminal) { - mTerminalInputIndex = mInputIndex - (inputIndexIncremented ? 1 : 0); - mTerminalOutputIndex = mOutputIndex; + mTerminalInputIndex = mInputIndex - (inputIndexIncremented ? 1 : 0); + mTerminalOutputIndex = mOutputIndex; + if (mNeedsToTraverseAllNodes && isTerminal) { incrementOutputIndex(); return TRAVERSE_ALL_ON_TERMINAL; } else { @@ -305,19 +296,36 @@ Correction::CorrectionType Correction::processSkipChar( } } +Correction::CorrectionType Correction::processUnrelatedCorrectionType() { + // Needs to set mTerminalInputIndex and mTerminalOutputIndex before returning any CorrectionType + mTerminalInputIndex = mInputIndex; + mTerminalOutputIndex = mOutputIndex; + return UNRELATED; +} + inline bool isEquivalentChar(ProximityInfo::ProximityType type) { return type == ProximityInfo::EQUIVALENT_CHAR; } +inline bool isProximityCharOrEquivalentChar(ProximityInfo::ProximityType type) { + return type == ProximityInfo::EQUIVALENT_CHAR + || type == ProximityInfo::NEAR_PROXIMITY_CHAR; +} + Correction::CorrectionType Correction::processCharAndCalcState( const int32_t c, const bool isTerminal) { const int correctionCount = (mSkippedCount + mExcessiveCount + mTransposedCount); + if (correctionCount > mMaxErrors) { + return processUnrelatedCorrectionType(); + } + // TODO: Change the limit if we'll allow two or more corrections const bool noCorrectionsHappenedSoFar = correctionCount == 0; const bool canTryCorrection = noCorrectionsHappenedSoFar; int proximityIndex = 0; mDistances[mOutputIndex] = NOT_A_DISTANCE; + // Skip checking this node if (mNeedsToTraverseAllNodes || isQuote(c)) { bool incremented = false; if (mLastCharExceeded && mInputIndex == mInputLength - 1) { @@ -342,6 +350,7 @@ Correction::CorrectionType Correction::processCharAndCalcState( return processSkipChar(c, isTerminal, incremented); } + // Check possible corrections. if (mExcessivePos >= 0) { if (mExcessiveCount == 0 && mExcessivePos < mOutputIndex) { mExcessivePos = mOutputIndex; @@ -382,30 +391,42 @@ Correction::CorrectionType Correction::processCharAndCalcState( incrementInputIndex(); } else { --mTransposedCount; - if (DEBUG_CORRECTION) { + if (DEBUG_CORRECTION + && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength) + && (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0 + || MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) { DUMP_WORD(mWord, mOutputIndex); - LOGI("UNRELATED(0): %d, %d, %d, %d, %c", mProximityCount, mSkippedCount, + AKLOGI("UNRELATED(0): %d, %d, %d, %d, %c", mProximityCount, mSkippedCount, mTransposedCount, mExcessiveCount, c); } - return UNRELATED; + return processUnrelatedCorrectionType(); } } // TODO: Change the limit if we'll allow two or more proximity chars with corrections - const bool checkProximityChars = noCorrectionsHappenedSoFar || mProximityCount == 0; + // Work around: When the mMaxErrors is 1, we only allow just one error + // including proximity correction. + const bool checkProximityChars = (mMaxErrors > 1) + ? (noCorrectionsHappenedSoFar || mProximityCount == 0) + : (noCorrectionsHappenedSoFar && mProximityCount == 0); + ProximityInfo::ProximityType matchedProximityCharId = secondTransposing ? ProximityInfo::EQUIVALENT_CHAR : mProximityInfo->getMatchedProximityId( mInputIndex, c, checkProximityChars, &proximityIndex); - if (ProximityInfo::UNRELATED_CHAR == matchedProximityCharId) { + if (ProximityInfo::UNRELATED_CHAR == matchedProximityCharId + || ProximityInfo::ADDITIONAL_PROXIMITY_CHAR == matchedProximityCharId) { if (canTryCorrection && mOutputIndex > 0 && mCorrectionStates[mOutputIndex].mProximityMatching && mCorrectionStates[mOutputIndex].mExceeding && isEquivalentChar(mProximityInfo->getMatchedProximityId( mInputIndex, mWord[mOutputIndex - 1], false))) { - if (DEBUG_CORRECTION) { - LOGI("CONVERSION p->e %c", mWord[mOutputIndex - 1]); + if (DEBUG_CORRECTION + && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength) + && (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0 + || MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) { + AKLOGI("CONVERSION p->e %c", mWord[mOutputIndex - 1]); } // Conversion p->e // Example: @@ -423,7 +444,11 @@ Correction::CorrectionType Correction::processCharAndCalcState( } } - if (ProximityInfo::UNRELATED_CHAR == matchedProximityCharId) { + if (ProximityInfo::UNRELATED_CHAR == matchedProximityCharId + || ProximityInfo::ADDITIONAL_PROXIMITY_CHAR == matchedProximityCharId) { + if (ProximityInfo::ADDITIONAL_PROXIMITY_CHAR == matchedProximityCharId) { + mAdditionalProximityMatching = true; + } // TODO: Optimize // As the current char turned out to be an unrelated char, // we will try other correction-types. Please note that mCorrectionStates[mOutputIndex] @@ -465,6 +490,18 @@ Correction::CorrectionType Correction::processCharAndCalcState( ++mSkippedCount; --mProximityCount; return processSkipChar(c, isTerminal, false); + } else if (mInputIndex - 1 < mInputLength + && mSkippedCount > 0 + && mCorrectionStates[mOutputIndex].mSkipping + && mCorrectionStates[mOutputIndex].mAdditionalProximityMatching + && isProximityCharOrEquivalentChar( + mProximityInfo->getMatchedProximityId(mInputIndex + 1, c, false))) { + // Conversion s->a + incrementInputIndex(); + --mSkippedCount; + mProximityMatching = true; + ++mProximityCount; + mDistances[mOutputIndex] = ADDITIONAL_PROXIMITY_CHAR_DISTANCE_INFO; } else if ((mExceeding || mTransposing) && mInputIndex - 1 < mInputLength && isEquivalentChar( mProximityInfo->getMatchedProximityId(mInputIndex + 1, c, false))) { @@ -475,17 +512,52 @@ Correction::CorrectionType Correction::processCharAndCalcState( ++mExcessiveCount; incrementInputIndex(); } + if (DEBUG_CORRECTION + && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength) + && (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0 + || MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) { + DUMP_WORD(mWord, mOutputIndex); + if (mTransposing) { + AKLOGI("TRANSPOSE: %d, %d, %d, %d, %c", mProximityCount, mSkippedCount, + mTransposedCount, mExcessiveCount, c); + } else { + AKLOGI("EXCEED: %d, %d, %d, %d, %c", mProximityCount, mSkippedCount, + mTransposedCount, mExcessiveCount, c); + } + } } else if (mSkipping) { // 3. Skip correction ++mSkippedCount; + if (DEBUG_CORRECTION + && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength) + && (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0 + || MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) { + AKLOGI("SKIP: %d, %d, %d, %d, %c", mProximityCount, mSkippedCount, + mTransposedCount, mExcessiveCount, c); + } return processSkipChar(c, isTerminal, false); + } else if (ProximityInfo::ADDITIONAL_PROXIMITY_CHAR == matchedProximityCharId) { + // As a last resort, use additional proximity characters + mProximityMatching = true; + ++mProximityCount; + mDistances[mOutputIndex] = ADDITIONAL_PROXIMITY_CHAR_DISTANCE_INFO; + if (DEBUG_CORRECTION + && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength) + && (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0 + || MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) { + AKLOGI("ADDITIONALPROX: %d, %d, %d, %d, %c", mProximityCount, mSkippedCount, + mTransposedCount, mExcessiveCount, c); + } } else { - if (DEBUG_CORRECTION) { + if (DEBUG_CORRECTION + && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength) + && (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0 + || MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) { DUMP_WORD(mWord, mOutputIndex); - LOGI("UNRELATED(1): %d, %d, %d, %d, %c", mProximityCount, mSkippedCount, + AKLOGI("UNRELATED(1): %d, %d, %d, %d, %c", mProximityCount, mSkippedCount, mTransposedCount, mExcessiveCount, c); } - return UNRELATED; + return processUnrelatedCorrectionType(); } } else if (secondTransposing) { // If inputIndex is greater than mInputLength, that means there is no @@ -500,6 +572,13 @@ Correction::CorrectionType Correction::processCharAndCalcState( ++mProximityCount; mDistances[mOutputIndex] = mProximityInfo->getNormalizedSquaredDistance(mInputIndex, proximityIndex); + if (DEBUG_CORRECTION + && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength) + && (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0 + || MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) { + AKLOGI("PROX: %d, %d, %d, %d, %c", mProximityCount, mSkippedCount, + mTransposedCount, mExcessiveCount, c); + } } addCharToCurrentWord(c); @@ -533,13 +612,17 @@ Correction::CorrectionType Correction::processCharAndCalcState( || isSameAsUserTypedLength) && isTerminal) { mTerminalInputIndex = mInputIndex - 1; mTerminalOutputIndex = mOutputIndex - 1; - if (DEBUG_CORRECTION) { + if (DEBUG_CORRECTION + && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == mInputLength) + && (MIN_OUTPUT_INDEX_FOR_DEBUG <= 0 || MIN_OUTPUT_INDEX_FOR_DEBUG < mOutputIndex)) { DUMP_WORD(mWord, mOutputIndex); - LOGI("ONTERMINAL(1): %d, %d, %d, %d, %c", mProximityCount, mSkippedCount, + AKLOGI("ONTERMINAL(1): %d, %d, %d, %d, %c", mProximityCount, mSkippedCount, mTransposedCount, mExcessiveCount, c); } return ON_TERMINAL; } else { + mTerminalInputIndex = mInputIndex - 1; + mTerminalOutputIndex = mOutputIndex - 1; return NOT_ON_TERMINAL; } } @@ -547,55 +630,6 @@ Correction::CorrectionType Correction::processCharAndCalcState( Correction::~Correction() { } -///////////////////////// -// static inline utils // -///////////////////////// - -static const int TWO_31ST_DIV_255 = S_INT_MAX / 255; -static inline int capped255MultForFullMatchAccentsOrCapitalizationDifference(const int num) { - return (num < TWO_31ST_DIV_255 ? 255 * num : S_INT_MAX); -} - -static const int TWO_31ST_DIV_2 = S_INT_MAX / 2; -inline static void multiplyIntCapped(const int multiplier, int *base) { - const int temp = *base; - if (temp != S_INT_MAX) { - // Branch if multiplier == 2 for the optimization - if (multiplier == 2) { - *base = TWO_31ST_DIV_2 >= temp ? temp << 1 : S_INT_MAX; - } else { - // TODO: This overflow check gives a wrong answer when, for example, - // temp = 2^16 + 1 and multiplier = 2^17 + 1. - // Fix this behavior. - const int tempRetval = temp * multiplier; - *base = tempRetval >= temp ? tempRetval : S_INT_MAX; - } - } -} - -inline static int powerIntCapped(const int base, const int n) { - if (n <= 0) return 1; - if (base == 2) { - return n < 31 ? 1 << n : S_INT_MAX; - } else { - int ret = base; - for (int i = 1; i < n; ++i) multiplyIntCapped(base, &ret); - return ret; - } -} - -inline static void multiplyRate(const int rate, int *freq) { - if (*freq != S_INT_MAX) { - if (*freq > 1000000) { - *freq /= 100; - multiplyIntCapped(rate, freq); - } else { - multiplyIntCapped(rate, freq); - *freq /= 100; - } - } -} - inline static int getQuoteCount(const unsigned short* word, const int length) { int quoteCount = 0; for (int i = 0; i < length; ++i) { @@ -607,13 +641,7 @@ inline static int getQuoteCount(const unsigned short* word, const int length) { } inline static bool isUpperCase(unsigned short c) { - if (c < sizeof(BASE_CHARS) / sizeof(BASE_CHARS[0])) { - c = BASE_CHARS[c]; - } - if (isupper(c)) { - return true; - } - return false; + return isAsciiUpper(toBaseChar(c)); } ////////////////////// @@ -622,9 +650,9 @@ inline static bool isUpperCase(unsigned short c) { /* static */ int Correction::RankingAlgorithm::calculateFinalFreq(const int inputIndex, const int outputIndex, - const int freq, int* editDistanceTable, const Correction* correction) { + const int freq, int* editDistanceTable, const Correction* correction, + const int inputLength) { const int excessivePos = correction->getExcessivePos(); - const int inputLength = correction->mInputLength; const int typedLetterMultiplier = correction->TYPED_LETTER_MULTIPLIER; const int fullWordMultiplier = correction->FULL_WORD_MULTIPLIER; const ProximityInfo *proximityInfo = correction->mProximityInfo; @@ -649,45 +677,55 @@ int Correction::RankingAlgorithm::calculateFinalFreq(const int inputIndex, const const unsigned short* word = correction->mWord; const bool skipped = skippedCount > 0; - const int quoteDiffCount = max(0, getQuoteCount(word, outputIndex + 1) + const int quoteDiffCount = max(0, getQuoteCount(word, outputLength) - getQuoteCount(proximityInfo->getPrimaryInputWord(), inputLength)); // TODO: Calculate edit distance for transposed and excessive int ed = 0; + if (DEBUG_DICT_FULL) { + dumpEditDistance10ForDebug(editDistanceTable, correction->mInputLength, outputLength); + } int adjustedProximityMatchedCount = proximityMatchedCount; int finalFreq = freq; + if (DEBUG_CORRECTION_FREQ + && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == inputLength)) { + AKLOGI("FinalFreq0: %d", finalFreq); + } // TODO: Optimize this. - // TODO: Ignoring edit distance for transposed char, for now - if (transposedCount == 0 && (proximityMatchedCount > 0 || skipped || excessiveCount > 0)) { - ed = getCurrentEditDistance(editDistanceTable, inputLength, outputIndex + 1); + if (transposedCount > 0 || proximityMatchedCount > 0 || skipped || excessiveCount > 0) { + ed = getCurrentEditDistance(editDistanceTable, correction->mInputLength, outputLength, + inputLength) - transposedCount; + const int matchWeight = powerIntCapped(typedLetterMultiplier, - max(inputLength, outputIndex + 1) - ed); + max(inputLength, outputLength) - ed); multiplyIntCapped(matchWeight, &finalFreq); // TODO: Demote further if there are two or more excessive chars with longer user input? - if (inputLength > outputIndex + 1) { + if (inputLength > outputLength) { multiplyRate(INPUT_EXCEEDS_OUTPUT_DEMOTION_RATE, &finalFreq); } ed = max(0, ed - quoteDiffCount); - - if (ed == 1 && (inputLength == outputIndex || inputLength == outputIndex + 2)) { - // Promote a word with just one skipped or excessive char - if (sameLength) { - multiplyRate(WORDS_WITH_JUST_ONE_CORRECTION_PROMOTION_RATE, &finalFreq); - } else { + adjustedProximityMatchedCount = min(max(0, ed - (outputLength - inputLength)), + proximityMatchedCount); + if (transposedCount < 1) { + if (ed == 1 && (inputLength == outputLength - 1 || inputLength == outputLength + 1)) { + // Promote a word with just one skipped or excessive char + if (sameLength) { + multiplyRate(WORDS_WITH_JUST_ONE_CORRECTION_PROMOTION_RATE + + WORDS_WITH_JUST_ONE_CORRECTION_PROMOTION_MULTIPLIER * outputLength, + &finalFreq); + } else { + multiplyIntCapped(typedLetterMultiplier, &finalFreq); + } + } else if (ed == 0) { multiplyIntCapped(typedLetterMultiplier, &finalFreq); + sameLength = true; } - } else if (ed == 0) { - multiplyIntCapped(typedLetterMultiplier, &finalFreq); - sameLength = true; } - adjustedProximityMatchedCount = min(max(0, ed - (outputIndex + 1 - inputLength)), - proximityMatchedCount); } else { - // TODO: Calculate the edit distance for transposed char const int matchWeight = powerIntCapped(typedLetterMultiplier, matchCount); multiplyIntCapped(matchWeight, &finalFreq); } @@ -707,7 +745,7 @@ int Correction::RankingAlgorithm::calculateFinalFreq(const int inputIndex, const / (10 * inputLength - WORDS_WITH_MISSING_CHARACTER_DEMOTION_START_POS_10X + 10); if (DEBUG_DICT_FULL) { - LOGI("Demotion rate for missing character is %d.", demotionRate); + AKLOGI("Demotion rate for missing character is %d.", demotionRate); } multiplyRate(demotionRate, &finalFreq); } @@ -720,8 +758,8 @@ int Correction::RankingAlgorithm::calculateFinalFreq(const int inputIndex, const if (excessiveCount > 0) { multiplyRate(WORDS_WITH_EXCESSIVE_CHARACTER_DEMOTION_RATE, &finalFreq); if (!lastCharExceeded && !proximityInfo->existsAdjacentProximityChars(excessivePos)) { - if (DEBUG_CORRECTION_FREQ) { - LOGI("Double excessive demotion"); + if (DEBUG_DICT_FULL) { + AKLOGI("Double excessive demotion"); } // If an excessive character is not adjacent to the left char or the right char, // we will demote this word. @@ -729,11 +767,14 @@ int Correction::RankingAlgorithm::calculateFinalFreq(const int inputIndex, const } } + const bool performTouchPositionCorrection = + CALIBRATE_SCORE_BY_TOUCH_COORDINATES && proximityInfo->touchPositionCorrectionEnabled() + && skippedCount == 0 && excessiveCount == 0 && transposedCount == 0; // Score calibration by touch coordinates is being done only for pure-fat finger typing error // cases. + int additionalProximityCount = 0; // TODO: Remove this constraint. - if (CALIBRATE_SCORE_BY_TOUCH_COORDINATES && proximityInfo->touchPositionCorrectionEnabled() - && skippedCount == 0 && excessiveCount == 0 && transposedCount == 0) { + if (performTouchPositionCorrection) { for (int i = 0; i < outputLength; ++i) { const int squaredDistance = correction->mDistances[i]; if (i < adjustedProximityMatchedCount) { @@ -744,40 +785,60 @@ int Correction::RankingAlgorithm::calculateFinalFreq(const int inputIndex, const static const float A = ZERO_DISTANCE_PROMOTION_RATE / 100.0f; static const float B = 1.0f; static const float C = 0.5f; + static const float MIN = 0.3f; static const float R1 = NEUTRAL_SCORE_SQUARED_RADIUS; static const float R2 = HALF_SCORE_SQUARED_RADIUS; const float x = (float)squaredDistance / ProximityInfo::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR; - const float factor = (x < R1) + const float factor = max((x < R1) ? (A * (R1 - x) + B * x) / R1 - : (B * (R2 - x) + C * (x - R1)) / (R2 - R1); + : (B * (R2 - x) + C * (x - R1)) / (R2 - R1), MIN); // factor is piecewise linear function like: // A -_ . // ^-_ . // B \ . - // \ . - // C \ . - // 0 R1 R2 - if (factor <= 0) { - return -1; - } + // \_ . + // C ------------. + // . + // 0 R1 R2 . multiplyRate((int)(factor * 100), &finalFreq); } else if (squaredDistance == PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO) { multiplyRate(WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq); + } else if (squaredDistance == ADDITIONAL_PROXIMITY_CHAR_DISTANCE_INFO) { + ++additionalProximityCount; + multiplyRate(WORDS_WITH_ADDITIONAL_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq); } } } else { + // Demote additional proximity characters + for (int i = 0; i < outputLength; ++i) { + const int squaredDistance = correction->mDistances[i]; + if (squaredDistance == ADDITIONAL_PROXIMITY_CHAR_DISTANCE_INFO) { + ++additionalProximityCount; + } + } // Promotion for a word with proximity characters for (int i = 0; i < adjustedProximityMatchedCount; ++i) { // A word with proximity corrections if (DEBUG_DICT_FULL) { - LOGI("Found a proximity correction."); + AKLOGI("Found a proximity correction."); } multiplyIntCapped(typedLetterMultiplier, &finalFreq); - multiplyRate(WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq); + if (i < additionalProximityCount) { + multiplyRate(WORDS_WITH_ADDITIONAL_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq); + } else { + multiplyRate(WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq); + } } } + // If the user types too many(three or more) proximity characters with additional proximity + // character,do not treat as the same length word. + if (sameLength && additionalProximityCount > 0 && (adjustedProximityMatchedCount >= 3 + || transposedCount > 0 || skipped || excessiveCount > 0)) { + sameLength = false; + } + const int errorCount = adjustedProximityMatchedCount > 0 ? adjustedProximityMatchedCount : (proximityMatchedCount + transposedCount); @@ -787,13 +848,15 @@ int Correction::RankingAlgorithm::calculateFinalFreq(const int inputIndex, const // Promotion for an exactly matched word if (ed == 0) { // Full exact match - if (sameLength && transposedCount == 0 && !skipped && excessiveCount == 0) { + if (sameLength && transposedCount == 0 && !skipped && excessiveCount == 0 + && quoteDiffCount == 0 && additionalProximityCount == 0) { finalFreq = capped255MultForFullMatchAccentsOrCapitalizationDifference(finalFreq); } } // Promote a word with no correction - if (proximityMatchedCount == 0 && transposedCount == 0 && !skipped && excessiveCount == 0) { + if (proximityMatchedCount == 0 && transposedCount == 0 && !skipped && excessiveCount == 0 + && additionalProximityCount == 0) { multiplyRate(FULL_MATCHED_WORDS_PROMOTION_RATE, &finalFreq); } @@ -832,71 +895,101 @@ int Correction::RankingAlgorithm::calculateFinalFreq(const int inputIndex, const } if (DEBUG_DICT_FULL) { - LOGI("calc: %d, %d", outputIndex, sameLength); + AKLOGI("calc: %d, %d", outputLength, sameLength); } - if (DEBUG_CORRECTION_FREQ) { - DUMP_WORD(correction->mWord, outputIndex + 1); - LOGI("FinalFreq: [P%d, S%d, T%d, E%d] %d, %d, %d, %d, %d", proximityMatchedCount, - skippedCount, transposedCount, excessiveCount, lastCharExceeded, sameLength, - quoteDiffCount, ed, finalFreq); + if (DEBUG_CORRECTION_FREQ + && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == inputLength)) { + DUMP_WORD(proximityInfo->getPrimaryInputWord(), inputLength); + DUMP_WORD(correction->mWord, outputLength); + AKLOGI("FinalFreq: [P%d, S%d, T%d, E%d, A%d] %d, %d, %d, %d, %d, %d", proximityMatchedCount, + skippedCount, transposedCount, excessiveCount, additionalProximityCount, + outputLength, lastCharExceeded, sameLength, quoteDiffCount, ed, finalFreq); } return finalFreq; } /* static */ -int Correction::RankingAlgorithm::calcFreqForSplitTwoWords( - const int firstFreq, const int secondFreq, const Correction* correction, - const unsigned short *word) { - const int spaceProximityPos = correction->mSpaceProximityPos; - const int missingSpacePos = correction->mMissingSpacePos; - if (DEBUG_DICT) { - int inputCount = 0; - if (spaceProximityPos >= 0) ++inputCount; - if (missingSpacePos >= 0) ++inputCount; - assert(inputCount <= 1); - } - const bool isSpaceProximity = spaceProximityPos >= 0; - const int inputLength = correction->mInputLength; - const int firstWordLength = isSpaceProximity ? spaceProximityPos : missingSpacePos; - const int secondWordLength = isSpaceProximity ? (inputLength - spaceProximityPos - 1) - : (inputLength - missingSpacePos); +int Correction::RankingAlgorithm::calcFreqForSplitMultipleWords( + const int *freqArray, const int *wordLengthArray, const int wordCount, + const Correction* correction, const bool isSpaceProximity, const unsigned short *word) { const int typedLetterMultiplier = correction->TYPED_LETTER_MULTIPLIER; bool firstCapitalizedWordDemotion = false; - if (firstWordLength >= 2) { - firstCapitalizedWordDemotion = isUpperCase(word[0]); - } - bool secondCapitalizedWordDemotion = false; - if (secondWordLength >= 2) { - secondCapitalizedWordDemotion = isUpperCase(word[firstWordLength + 1]); + + { + // TODO: Handle multiple capitalized word demotion properly + const int firstWordLength = wordLengthArray[0]; + const int secondWordLength = wordLengthArray[1]; + if (firstWordLength >= 2) { + firstCapitalizedWordDemotion = isUpperCase(word[0]); + } + + if (secondWordLength >= 2) { + // FIXME: word[firstWordLength + 1] is incorrect. + secondCapitalizedWordDemotion = isUpperCase(word[firstWordLength + 1]); + } } + const bool capitalizedWordDemotion = firstCapitalizedWordDemotion ^ secondCapitalizedWordDemotion; - if (DEBUG_DICT_FULL) { - LOGI("Two words: %c, %c, %d", word[0], word[firstWordLength + 1], capitalizedWordDemotion); + int totalLength = 0; + int totalFreq = 0; + for (int i = 0; i < wordCount; ++i){ + const int wordLength = wordLengthArray[i]; + if (wordLength <= 0) { + return 0; + } + totalLength += wordLength; + const int demotionRate = 100 - TWO_WORDS_CORRECTION_DEMOTION_BASE / (wordLength + 1); + int tempFirstFreq = freqArray[i]; + multiplyRate(demotionRate, &tempFirstFreq); + totalFreq += tempFirstFreq; } - if (firstWordLength == 0 || secondWordLength == 0) { + if (totalLength <= 0 || totalFreq <= 0) { return 0; } - const int firstDemotionRate = 100 - 100 / (firstWordLength + 1); - int tempFirstFreq = firstFreq; - multiplyRate(firstDemotionRate, &tempFirstFreq); - - const int secondDemotionRate = 100 - 100 / (secondWordLength + 1); - int tempSecondFreq = secondFreq; - multiplyRate(secondDemotionRate, &tempSecondFreq); - - const int totalLength = firstWordLength + secondWordLength; + // TODO: Currently totalFreq is adjusted to two word metrix. // Promote pairFreq with multiplying by 2, because the word length is the same as the typed // length. - int totalFreq = tempFirstFreq + tempSecondFreq; + totalFreq = totalFreq * 2 / wordCount; + if (wordCount > 2) { + // Safety net for 3+ words -- Caveats: many heuristics and workarounds here. + int oneLengthCounter = 0; + int twoLengthCounter = 0; + for (int i = 0; i < wordCount; ++i) { + const int wordLength = wordLengthArray[i]; + // TODO: Use bigram instead of this safety net + if (i < wordCount - 1) { + const int nextWordLength = wordLengthArray[i + 1]; + if (wordLength == 1 && nextWordLength == 2) { + // Safety net to filter 1 length and 2 length sequential words + return 0; + } + } + const int freq = freqArray[i]; + // Demote too short weak words + if (wordLength <= 4 && freq <= MAX_FREQ * 2 / 3 /* heuristic... */) { + multiplyRate(100 * freq / MAX_FREQ, &totalFreq); + } + if (wordLength == 1) { + ++oneLengthCounter; + } else if (wordLength == 2) { + ++twoLengthCounter; + } + if (oneLengthCounter >= 2 || (oneLengthCounter + twoLengthCounter) >= 4) { + // Safety net to filter too many short words + return 0; + } + } + multiplyRate(MULTIPLE_WORDS_DEMOTION_RATE, &totalFreq); + } // This is a workaround to try offsetting the not-enough-demotion which will be done in // calcNormalizedScore in Utils.java. @@ -923,19 +1016,128 @@ int Correction::RankingAlgorithm::calcFreqForSplitTwoWords( if (isSpaceProximity) { // A word pair with one space proximity correction if (DEBUG_DICT) { - LOGI("Found a word pair with space proximity correction."); + AKLOGI("Found a word pair with space proximity correction."); } multiplyIntCapped(typedLetterMultiplier, &totalFreq); multiplyRate(WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE, &totalFreq); } - multiplyRate(WORDS_WITH_MISSING_SPACE_CHARACTER_DEMOTION_RATE, &totalFreq); + if (isSpaceProximity) { + multiplyRate(WORDS_WITH_MISTYPED_SPACE_DEMOTION_RATE, &totalFreq); + } else { + multiplyRate(WORDS_WITH_MISSING_SPACE_CHARACTER_DEMOTION_RATE, &totalFreq); + } if (capitalizedWordDemotion) { multiplyRate(TWO_WORDS_CAPITALIZED_DEMOTION_RATE, &totalFreq); } + if (DEBUG_CORRECTION_FREQ) { + AKLOGI("Multiple words (%d, %d) (%d, %d) %d, %d", freqArray[0], freqArray[1], + wordLengthArray[0], wordLengthArray[1], capitalizedWordDemotion, totalFreq); + DUMP_WORD(word, wordLengthArray[0]); + } + return totalFreq; } +/* Damerau-Levenshtein distance */ +inline static int editDistanceInternal( + int* editDistanceTable, const unsigned short* before, + const int beforeLength, const unsigned short* after, const int afterLength) { + // dp[li][lo] dp[a][b] = dp[ a * lo + b] + int* dp = editDistanceTable; + const int li = beforeLength + 1; + const int lo = afterLength + 1; + for (int i = 0; i < li; ++i) { + dp[lo * i] = i; + } + for (int i = 0; i < lo; ++i) { + dp[i] = i; + } + + for (int i = 0; i < li - 1; ++i) { + for (int j = 0; j < lo - 1; ++j) { + const uint32_t ci = toBaseLowerCase(before[i]); + const uint32_t co = toBaseLowerCase(after[j]); + const uint16_t cost = (ci == co) ? 0 : 1; + dp[(i + 1) * lo + (j + 1)] = min(dp[i * lo + (j + 1)] + 1, + min(dp[(i + 1) * lo + j] + 1, dp[i * lo + j] + cost)); + if (i > 0 && j > 0 && ci == toBaseLowerCase(after[j - 1]) + && co == toBaseLowerCase(before[i - 1])) { + dp[(i + 1) * lo + (j + 1)] = min( + dp[(i + 1) * lo + (j + 1)], dp[(i - 1) * lo + (j - 1)] + cost); + } + } + } + + if (DEBUG_EDIT_DISTANCE) { + AKLOGI("IN = %d, OUT = %d", beforeLength, afterLength); + for (int i = 0; i < li; ++i) { + for (int j = 0; j < lo; ++j) { + AKLOGI("EDIT[%d][%d], %d", i, j, dp[i * lo + j]); + } + } + } + return dp[li * lo - 1]; +} + +int Correction::RankingAlgorithm::editDistance(const unsigned short* before, + const int beforeLength, const unsigned short* after, const int afterLength) { + int table[(beforeLength + 1) * (afterLength + 1)]; + return editDistanceInternal(table, before, beforeLength, after, afterLength); +} + + +// In dictionary.cpp, getSuggestion() method, +// suggestion scores are computed using the below formula. +// original score +// := pow(mTypedLetterMultiplier (this is defined 2), +// (the number of matched characters between typed word and suggested word)) +// * (individual word's score which defined in the unigram dictionary, +// and this score is defined in range [0, 255].) +// Then, the following processing is applied. +// - If the dictionary word is matched up to the point of the user entry +// (full match up to min(before.length(), after.length()) +// => Then multiply by FULL_MATCHED_WORDS_PROMOTION_RATE (this is defined 1.2) +// - If the word is a true full match except for differences in accents or +// capitalization, then treat it as if the score was 255. +// - If before.length() == after.length() +// => multiply by mFullWordMultiplier (this is defined 2)) +// So, maximum original score is pow(2, min(before.length(), after.length())) * 255 * 2 * 1.2 +// For historical reasons we ignore the 1.2 modifier (because the measure for a good +// autocorrection threshold was done at a time when it didn't exist). This doesn't change +// the result. +// So, we can normalize original score by dividing pow(2, min(b.l(),a.l())) * 255 * 2. + +/* static */ +double Correction::RankingAlgorithm::calcNormalizedScore(const unsigned short* before, + const int beforeLength, const unsigned short* after, const int afterLength, + const int score) { + if (0 == beforeLength || 0 == afterLength) { + return 0; + } + const int distance = editDistance(before, beforeLength, after, afterLength); + int spaceCount = 0; + for (int i = 0; i < afterLength; ++i) { + if (after[i] == CODE_SPACE) { + ++spaceCount; + } + } + + if (spaceCount == afterLength) { + return 0; + } + + const double maxScore = score >= S_INT_MAX ? S_INT_MAX : MAX_INITIAL_SCORE + * pow((double)TYPED_LETTER_MULTIPLIER, + (double)min(beforeLength, afterLength - spaceCount)) * FULL_WORD_MULTIPLIER; + + // add a weight based on edit distance. + // distance <= max(afterLength, beforeLength) == afterLength, + // so, 0 <= distance / afterLength <= 1 + const double weight = 1.0 - (double) distance / afterLength; + return (score / maxScore) * weight; +} + } // namespace latinime diff --git a/native/src/correction.h b/native/src/correction.h index d4e99f0ce..2114eff4b 100644 --- a/native/src/correction.h +++ b/native/src/correction.h @@ -27,8 +27,7 @@ namespace latinime { class ProximityInfo; class Correction { - -public: + public: typedef enum { TRAVERSE_ALL_ON_TERMINAL, TRAVERSE_ALL_NOT_ON_TERMINAL, @@ -37,6 +36,55 @@ public: NOT_ON_TERMINAL } CorrectionType; + ///////////////////////// + // static inline utils // + ///////////////////////// + + static const int TWO_31ST_DIV_255 = S_INT_MAX / 255; + static inline int capped255MultForFullMatchAccentsOrCapitalizationDifference(const int num) { + return (num < TWO_31ST_DIV_255 ? 255 * num : S_INT_MAX); + } + + static const int TWO_31ST_DIV_2 = S_INT_MAX / 2; + inline static void multiplyIntCapped(const int multiplier, int *base) { + const int temp = *base; + if (temp != S_INT_MAX) { + // Branch if multiplier == 2 for the optimization + if (multiplier == 2) { + *base = TWO_31ST_DIV_2 >= temp ? temp << 1 : S_INT_MAX; + } else { + // TODO: This overflow check gives a wrong answer when, for example, + // temp = 2^16 + 1 and multiplier = 2^17 + 1. + // Fix this behavior. + const int tempRetval = temp * multiplier; + *base = tempRetval >= temp ? tempRetval : S_INT_MAX; + } + } + } + + inline static int powerIntCapped(const int base, const int n) { + if (n <= 0) return 1; + if (base == 2) { + return n < 31 ? 1 << n : S_INT_MAX; + } else { + int ret = base; + for (int i = 1; i < n; ++i) multiplyIntCapped(base, &ret); + return ret; + } + } + + inline static void multiplyRate(const int rate, int *freq) { + if (*freq != S_INT_MAX) { + if (*freq > 1000000) { + *freq /= 100; + multiplyIntCapped(rate, freq); + } else { + multiplyIntCapped(rate, freq); + *freq /= 100; + } + } + } + Correction(const int typedLetterMultiplier, const int fullWordMultiplier); void initCorrection( const ProximityInfo *pi, const int inputLength, const int maxWordLength); @@ -44,11 +92,11 @@ public: // TODO: remove void setCorrectionParams(const int skipPos, const int excessivePos, const int transposedPos, - const int spaceProximityPos, const int missingSpacePos, const bool useFullEditDistance); + const int spaceProximityPos, const int missingSpacePos, const bool useFullEditDistance, + const bool doAutoCompletion, const int maxErrors); void checkState(); bool initProcessState(const int index); - int getOutputIndex(); int getInputIndex(); virtual ~Correction(); @@ -73,9 +121,12 @@ public: bool needsToPrune() const; - int getFreqForSplitTwoWords( - const int firstFreq, const int secondFreq, const unsigned short *word); + int getFreqForSplitMultipleWords( + const int *freqArray, const int *wordLengthArray, const int wordCount, + const bool isSpaceProximity, const unsigned short *word); int getFinalFreq(const int freq, unsigned short **word, int* wordLength); + int getFinalFreqForSubQueue(const int freq, unsigned short **word, int* wordLength, + const int inputLength); CorrectionType processCharAndCalcState(const int32_t c, const bool isTerminal); @@ -94,21 +145,44 @@ public: inline int getTreeParentIndex(const int index) const { return mCorrectionStates[index].mParentIndex; } -private: + + class RankingAlgorithm { + public: + static int calculateFinalFreq(const int inputIndex, const int depth, + const int freq, int *editDistanceTable, const Correction* correction, + const int inputLength); + static int calcFreqForSplitMultipleWords(const int *freqArray, const int *wordLengthArray, + const int wordCount, const Correction* correction, const bool isSpaceProximity, + const unsigned short *word); + static double calcNormalizedScore(const unsigned short* before, const int beforeLength, + const unsigned short* after, const int afterLength, const int score); + static int editDistance(const unsigned short* before, + const int beforeLength, const unsigned short* after, const int afterLength); + private: + static const int CODE_SPACE = ' '; + static const int MAX_INITIAL_SCORE = 255; + static const int TYPED_LETTER_MULTIPLIER = 2; + static const int FULL_WORD_MULTIPLIER = 2; + }; + + private: inline void incrementInputIndex(); inline void incrementOutputIndex(); - inline bool needsToTraverseAllNodes(); inline void startToTraverseAllNodes(); inline bool isQuote(const unsigned short c); inline CorrectionType processSkipChar( const int32_t c, const bool isTerminal, const bool inputIndexIncremented); + inline CorrectionType processUnrelatedCorrectionType(); inline void addCharToCurrentWord(const int32_t c); + inline int getFinalFreqInternal(const int freq, unsigned short **word, int* wordLength, + const int inputLength); const int TYPED_LETTER_MULTIPLIER; const int FULL_WORD_MULTIPLIER; const ProximityInfo *mProximityInfo; bool mUseFullEditDistance; + bool mDoAutoCompletion; int mMaxEditDistance; int mMaxDepth; int mInputLength; @@ -116,6 +190,7 @@ private: int mMissingSpacePos; int mTerminalInputIndex; int mTerminalOutputIndex; + int mMaxErrors; // The following arrays are state buffer. unsigned short mWord[MAX_WORD_LENGTH_INTERNAL]; @@ -146,17 +221,11 @@ private: bool mMatching; bool mProximityMatching; + bool mAdditionalProximityMatching; bool mExceeding; bool mTransposing; bool mSkipping; - class RankingAlgorithm { - public: - static int calculateFinalFreq(const int inputIndex, const int depth, - const int freq, int *editDistanceTable, const Correction* correction); - static int calcFreqForSplitTwoWords(const int firstFreq, const int secondFreq, - const Correction* correction, const unsigned short *word); - }; }; } // namespace latinime #endif // LATINIME_CORRECTION_H diff --git a/native/src/correction_state.h b/native/src/correction_state.h index c04146e54..5b2cbd3a2 100644 --- a/native/src/correction_state.h +++ b/native/src/correction_state.h @@ -47,9 +47,9 @@ struct CorrectionState { bool mExceeding; bool mSkipping; bool mProximityMatching; + bool mAdditionalProximityMatching; bool mNeedsToTraverseAllNodes; - }; inline static void initCorrectionState(CorrectionState *state, const int rootPos, @@ -77,7 +77,7 @@ inline static void initCorrectionState(CorrectionState *state, const int rootPos state->mTransposing = false; state->mExceeding = false; state->mSkipping = false; - + state->mAdditionalProximityMatching = false; } } // namespace latinime diff --git a/native/src/debug.h b/native/src/debug.h index 38b2f107a..b13052c95 100644 --- a/native/src/debug.h +++ b/native/src/debug.h @@ -42,7 +42,7 @@ static inline unsigned char* convertToUnibyteStringAndReplaceLastChar(unsigned s static inline void LOGI_S16(unsigned short* string, const unsigned int length) { unsigned char tmp_buffer[length]; convertToUnibyteString(string, tmp_buffer, length); - LOGI(">> %s", tmp_buffer); + AKLOGI(">> %s", tmp_buffer); // The log facility is throwing out log that comes too fast. The following // is a dirty way of slowing down processing so that we can see all log. // TODO : refactor this in a blocking log or something. @@ -53,7 +53,7 @@ static inline void LOGI_S16_PLUS(unsigned short* string, const unsigned int leng unsigned char c) { unsigned char tmp_buffer[length+1]; convertToUnibyteStringAndReplaceLastChar(string, tmp_buffer, length, c); - LOGI(">> %s", tmp_buffer); + AKLOGI(">> %s", tmp_buffer); // Likewise // usleep(10); } @@ -64,7 +64,7 @@ static inline void printDebug(const char* tag, int* codes, int codesSize, int MA buf[codesSize] = 0; while (--codesSize >= 0) buf[codesSize] = (unsigned char)codes[codesSize * MAX_PROXIMITY_CHARS]; - LOGI("%s, WORD = %s", tag, buf); + AKLOGI("%s, WORD = %s", tag, buf); free(buf); } diff --git a/native/src/defines.h b/native/src/defines.h index ef1beb92f..ffadb11c5 100644 --- a/native/src/defines.h +++ b/native/src/defines.h @@ -20,15 +20,32 @@ #if defined(FLAG_DO_PROFILE) || defined(FLAG_DBG) #include <cutils/log.h> +#define AKLOGE ALOGE +#define AKLOGI ALOGI + +#define DUMP_WORD(word, length) do { dumpWord(word, length); } while(0) + +static char charBuf[50]; + +static void dumpWord(const unsigned short* word, const int length) { + for (int i = 0; i < length; ++i) { + charBuf[i] = word[i]; + } + charBuf[length] = 0; + AKLOGI("[ %s ]", charBuf); +} + #else -#define LOGE(fmt, ...) -#define LOGI(fmt, ...) +#define AKLOGE(fmt, ...) +#define AKLOGI(fmt, ...) +#define DUMP_WORD(word, length) #endif #ifdef FLAG_DO_PROFILE // Profiler #include <cutils/log.h> #include <time.h> + #define PROF_BUF_SIZE 100 static double profile_buf[PROF_BUF_SIZE]; static double profile_old[PROF_BUF_SIZE]; @@ -42,8 +59,8 @@ static unsigned int profile_counter[PROF_BUF_SIZE]; #define PROF_CLOSE do { PROF_END(PROF_BUF_SIZE - 1); PROF_OUTALL; } while(0) #define PROF_END(prof_buf_id) profile_buf[prof_buf_id] += ((clock()) - profile_old[prof_buf_id]) #define PROF_CLOCKOUT(prof_buf_id) \ - LOGI("%s : clock is %f", __FUNCTION__, (clock() - profile_old[prof_buf_id])) -#define PROF_OUTALL do { LOGI("--- %s ---", __FUNCTION__); prof_out(); } while(0) + AKLOGI("%s : clock is %f", __FUNCTION__, (clock() - profile_old[prof_buf_id])) +#define PROF_OUTALL do { AKLOGI("--- %s ---", __FUNCTION__); prof_out(); } while(0) static void prof_reset(void) { for (int i = 0; i < PROF_BUF_SIZE; ++i) { @@ -55,9 +72,9 @@ static void prof_reset(void) { static void prof_out(void) { if (profile_counter[PROF_BUF_SIZE - 1] != 1) { - LOGI("Error: You must call PROF_OPEN before PROF_CLOSE."); + AKLOGI("Error: You must call PROF_OPEN before PROF_CLOSE."); } - LOGI("Total time is %6.3f ms.", + AKLOGI("Total time is %6.3f ms.", profile_buf[PROF_BUF_SIZE - 1] * 1000 / (double)CLOCKS_PER_SEC); double all = 0; for (int i = 0; i < PROF_BUF_SIZE - 1; ++i) { @@ -66,7 +83,7 @@ static void prof_out(void) { if (all == 0) all = 1; for (int i = 0; i < PROF_BUF_SIZE - 1; ++i) { if (profile_buf[i] != 0) { - LOGI("(%d): Used %4.2f%%, %8.4f ms. Called %d times.", + AKLOGI("(%d): Used %4.2f%%, %8.4f ms. Called %d times.", i, (profile_buf[i] * 100 / all), profile_buf[i] * 1000 / (double)CLOCKS_PER_SEC, profile_counter[i]); } @@ -98,21 +115,10 @@ static void prof_out(void) { #define DEBUG_SHOW_FOUND_WORD false #define DEBUG_NODE DEBUG_DICT_FULL #define DEBUG_TRACE DEBUG_DICT_FULL -#define DEBUG_PROXIMITY_INFO true +#define DEBUG_PROXIMITY_INFO false #define DEBUG_CORRECTION false -#define DEBUG_CORRECTION_FREQ true - -#define DUMP_WORD(word, length) do { dumpWord(word, length); } while(0) - -static char charBuf[50]; - -static void dumpWord(const unsigned short* word, const int length) { - for (int i = 0; i < length; ++i) { - charBuf[i] = word[i]; - } - charBuf[length] = 0; - LOGI("[ %s ]", charBuf); -} +#define DEBUG_CORRECTION_FREQ false +#define DEBUG_WORDS_PRIORITY_QUEUE false #else // FLAG_DBG @@ -125,8 +131,8 @@ static void dumpWord(const unsigned short* word, const int length) { #define DEBUG_PROXIMITY_INFO false #define DEBUG_CORRECTION false #define DEBUG_CORRECTION_FREQ false +#define DEBUG_WORDS_PRIORITY_QUEUE false -#define DUMP_WORD(word, length) #endif // FLAG_DBG @@ -163,58 +169,88 @@ static void dumpWord(const unsigned short* word, const int length) { #define NOT_VALID_WORD -99 #define NOT_A_CHARACTER -1 #define NOT_A_DISTANCE -1 +#define NOT_A_COORDINATE -1 #define EQUIVALENT_CHAR_WITHOUT_DISTANCE_INFO -2 #define PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO -3 +#define ADDITIONAL_PROXIMITY_CHAR_DISTANCE_INFO -4 #define NOT_A_INDEX -1 +#define NOT_A_FREQUENCY -1 #define KEYCODE_SPACE ' ' #define CALIBRATE_SCORE_BY_TOUCH_COORDINATES true #define SUGGEST_WORDS_WITH_MISSING_CHARACTER true -#define SUGGEST_WORDS_WITH_MISSING_SPACE_CHARACTER true #define SUGGEST_WORDS_WITH_EXCESSIVE_CHARACTER true #define SUGGEST_WORDS_WITH_TRANSPOSED_CHARACTERS true -#define SUGGEST_WORDS_WITH_SPACE_PROXIMITY true +#define SUGGEST_MULTIPLE_WORDS true // The following "rate"s are used as a multiplier before dividing by 100, so they are in percent. #define WORDS_WITH_MISSING_CHARACTER_DEMOTION_RATE 80 #define WORDS_WITH_MISSING_CHARACTER_DEMOTION_START_POS_10X 12 -#define WORDS_WITH_MISSING_SPACE_CHARACTER_DEMOTION_RATE 67 +#define WORDS_WITH_MISSING_SPACE_CHARACTER_DEMOTION_RATE 58 +#define WORDS_WITH_MISTYPED_SPACE_DEMOTION_RATE 50 #define WORDS_WITH_EXCESSIVE_CHARACTER_DEMOTION_RATE 75 #define WORDS_WITH_EXCESSIVE_CHARACTER_OUT_OF_PROXIMITY_DEMOTION_RATE 75 -#define WORDS_WITH_TRANSPOSED_CHARACTERS_DEMOTION_RATE 60 +#define WORDS_WITH_TRANSPOSED_CHARACTERS_DEMOTION_RATE 70 #define FULL_MATCHED_WORDS_PROMOTION_RATE 120 #define WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE 90 +#define WORDS_WITH_ADDITIONAL_PROXIMITY_CHARACTER_DEMOTION_RATE 70 #define WORDS_WITH_MATCH_SKIP_PROMOTION_RATE 105 -#define WORDS_WITH_JUST_ONE_CORRECTION_PROMOTION_RATE 160 +#define WORDS_WITH_JUST_ONE_CORRECTION_PROMOTION_RATE 148 +#define WORDS_WITH_JUST_ONE_CORRECTION_PROMOTION_MULTIPLIER 3 #define CORRECTION_COUNT_RATE_DEMOTION_RATE_BASE 45 #define INPUT_EXCEEDS_OUTPUT_DEMOTION_RATE 70 #define FIRST_CHAR_DIFFERENT_DEMOTION_RATE 96 #define TWO_WORDS_CAPITALIZED_DEMOTION_RATE 50 +#define TWO_WORDS_CORRECTION_DEMOTION_BASE 80 +#define TWO_WORDS_PLUS_OTHER_ERROR_CORRECTION_DEMOTION_DIVIDER 1 #define ZERO_DISTANCE_PROMOTION_RATE 110 #define NEUTRAL_SCORE_SQUARED_RADIUS 8.0f #define HALF_SCORE_SQUARED_RADIUS 32.0f +#define MAX_FREQ 255 -// This should be greater than or equal to MAX_WORD_LENGTH defined in BinaryDictionary.java +// This must be greater than or equal to MAX_WORD_LENGTH defined in BinaryDictionary.java // This is only used for the size of array. Not to be used in c functions. #define MAX_WORD_LENGTH_INTERNAL 48 +// This must be equal to ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE in KeyDetector.java +#define ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE 2 + +// Word limit for sub queues used in WordsPriorityQueuePool. Sub queues are temporary queues used +// for better performance. +// Holds up to 1 candidate for each word +#define SUB_QUEUE_MAX_WORDS 1 +#define SUB_QUEUE_MAX_COUNT 10 +#define SUB_QUEUE_MIN_WORD_LENGTH 4 +#define MULTIPLE_WORDS_SUGGESTION_MAX_WORDS 10 +#define MULTIPLE_WORDS_DEMOTION_RATE 80 +#define MIN_INPUT_LENGTH_FOR_THREE_OR_MORE_WORDS_CORRECTION 6 + +#define TWO_WORDS_CORRECTION_WITH_OTHER_ERROR_THRESHOLD 0.39 +#define START_TWO_WORDS_CORRECTION_THRESHOLD 0.22 + #define MAX_DEPTH_MULTIPLIER 3 +#define FIRST_WORD_INDEX 0 + // TODO: Reduce this constant if possible; check the maximum number of umlauts in the same German // word in the dictionary #define DEFAULT_MAX_UMLAUT_SEARCH_DEPTH 5 // Minimum suggest depth for one word for all cases except for missing space suggestions. #define MIN_SUGGEST_DEPTH 1 -#define MIN_USER_TYPED_LENGTH_FOR_MISSING_SPACE_SUGGESTION 3 +#define MIN_USER_TYPED_LENGTH_FOR_MULTIPLE_WORD_SUGGESTION 3 #define MIN_USER_TYPED_LENGTH_FOR_EXCESSIVE_CHARACTER_SUGGESTION 3 -#define min(a,b) ((a)<(b)?(a):(b)) -#define max(a,b) ((a)>(b)?(a):(b)) +template<typename T> inline T min(T a, T b) { return a < b ? a : b; } +template<typename T> inline T max(T a, T b) { return a > b ? a : b; } // The ratio of neutral area radius to sweet spot radius. #define NEUTRAL_AREA_RADIUS_RATIO 1.3f +// DEBUG +#define INPUTLENGTH_FOR_DEBUG -1 +#define MIN_OUTPUT_INDEX_FOR_DEBUG -1 + #endif // LATINIME_DEFINES_H diff --git a/native/src/dictionary.cpp b/native/src/dictionary.cpp index a49769bdb..822c2151d 100644 --- a/native/src/dictionary.cpp +++ b/native/src/dictionary.cpp @@ -33,11 +33,14 @@ Dictionary::Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, IS_LATEST_DICT_VERSION((((unsigned char*) dict)[0] & 0xFF) >= DICTIONARY_VERSION_MIN) { if (DEBUG_DICT) { if (MAX_WORD_LENGTH_INTERNAL < maxWordLength) { - LOGI("Max word length (%d) is greater than %d", + AKLOGI("Max word length (%d) is greater than %d", maxWordLength, MAX_WORD_LENGTH_INTERNAL); - LOGI("IN NATIVE SUGGEST Version: %d", (mDict[0] & 0xFF)); + AKLOGI("IN NATIVE SUGGEST Version: %d", (mDict[0] & 0xFF)); } } + mCorrection = new Correction(typedLetterMultiplier, fullWordMultiplier); + mWordsPriorityQueuePool = new WordsPriorityQueuePool( + maxWords, SUB_QUEUE_MAX_WORDS, maxWordLength); mUnigramDictionary = new UnigramDictionary(mDict, typedLetterMultiplier, fullWordMultiplier, maxWordLength, maxWords, maxAlternatives, IS_LATEST_DICT_VERSION); mBigramDictionary = new BigramDictionary(mDict, maxWordLength, maxAlternatives, @@ -45,6 +48,8 @@ Dictionary::Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, } Dictionary::~Dictionary() { + delete mCorrection; + delete mWordsPriorityQueuePool; delete mUnigramDictionary; delete mBigramDictionary; } diff --git a/native/src/dictionary.h b/native/src/dictionary.h index d5de0083a..90d7148d5 100644 --- a/native/src/dictionary.h +++ b/native/src/dictionary.h @@ -17,22 +17,25 @@ #ifndef LATINIME_DICTIONARY_H #define LATINIME_DICTIONARY_H -#include "basechars.h" #include "bigram_dictionary.h" #include "char_utils.h" +#include "correction.h" #include "defines.h" #include "proximity_info.h" #include "unigram_dictionary.h" +#include "words_priority_queue_pool.h" namespace latinime { class Dictionary { -public: + public: Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, int typedLetterMultipler, int fullWordMultiplier, int maxWordLength, int maxWords, int maxAlternatives); + int getSuggestions(ProximityInfo *proximityInfo, int *xcoordinates, int *ycoordinates, int *codes, int codesSize, int flags, unsigned short *outWords, int *frequencies) { - return mUnigramDictionary->getSuggestions(proximityInfo, xcoordinates, ycoordinates, codes, + return mUnigramDictionary->getSuggestions(proximityInfo, mWordsPriorityQueuePool, + mCorrection, xcoordinates, ycoordinates, codes, codesSize, flags, outWords, frequencies); } @@ -53,19 +56,9 @@ public: // public static utility methods // static inline methods should be defined in the header file - static unsigned short getChar(const unsigned char *dict, int *pos); - static int getCount(const unsigned char *dict, int *pos); - static bool getTerminal(const unsigned char *dict, int *pos); - static int getAddress(const unsigned char *dict, int *pos); - static int getFreq(const unsigned char *dict, const bool isLatestDictVersion, int *pos); static int wideStrLen(unsigned short *str); - // returns next sibling's position - static int setDictionaryValues(const unsigned char *dict, const bool isLatestDictVersion, - const int pos, unsigned short *c, int *childrenPosition, - bool *terminal, int *freq); - static inline unsigned short toBaseLowerCase(unsigned short c); -private: + private: bool hasBigram(); const unsigned char *mDict; @@ -79,60 +72,12 @@ private: const bool IS_LATEST_DICT_VERSION; UnigramDictionary *mUnigramDictionary; BigramDictionary *mBigramDictionary; + WordsPriorityQueuePool *mWordsPriorityQueuePool; + Correction *mCorrection; }; // public static utility methods // static inline methods should be defined in the header file -inline unsigned short Dictionary::getChar(const unsigned char *dict, int *pos) { - unsigned short ch = (unsigned short) (dict[(*pos)++] & 0xFF); - // If the code is 255, then actual 16 bit code follows (in big endian) - if (ch == 0xFF) { - ch = ((dict[*pos] & 0xFF) << 8) | (dict[*pos + 1] & 0xFF); - (*pos) += 2; - } - return ch; -} - -inline int Dictionary::getCount(const unsigned char *dict, int *pos) { - return dict[(*pos)++] & 0xFF; -} - -inline bool Dictionary::getTerminal(const unsigned char *dict, int *pos) { - return (dict[*pos] & FLAG_TERMINAL_MASK) > 0; -} - -inline int Dictionary::getAddress(const unsigned char *dict, int *pos) { - int address = 0; - if ((dict[*pos] & FLAG_ADDRESS_MASK) == 0) { - *pos += 1; - } else { - address += (dict[*pos] & (ADDRESS_MASK >> 16)) << 16; - address += (dict[*pos + 1] & 0xFF) << 8; - address += (dict[*pos + 2] & 0xFF); - *pos += 3; - } - return address; -} - -inline int Dictionary::getFreq(const unsigned char *dict, - const bool isLatestDictVersion, int *pos) { - int freq = dict[(*pos)++] & 0xFF; - if (isLatestDictVersion) { - // skipping bigram - int bigramExist = (dict[*pos] & FLAG_BIGRAM_READ); - if (bigramExist > 0) { - int nextBigramExist = 1; - while (nextBigramExist > 0) { - (*pos) += 3; - nextBigramExist = (dict[(*pos)++] & FLAG_BIGRAM_CONTINUED); - } - } else { - (*pos)++; - } - } - return freq; -} - inline int Dictionary::wideStrLen(unsigned short *str) { if (!str) return 0; unsigned short *end = str; @@ -140,35 +85,6 @@ inline int Dictionary::wideStrLen(unsigned short *str) { end++; return end - str; } - -inline int Dictionary::setDictionaryValues(const unsigned char *dict, - const bool isLatestDictVersion, const int pos, unsigned short *c,int *childrenPosition, - bool *terminal, int *freq) { - int position = pos; - // -- at char - *c = Dictionary::getChar(dict, &position); - // -- at flag/add - *terminal = Dictionary::getTerminal(dict, &position); - *childrenPosition = Dictionary::getAddress(dict, &position); - // -- after address or flag - *freq = (*terminal) ? Dictionary::getFreq(dict, isLatestDictVersion, &position) : 1; - // returns next sibling's position - return position; -} - - -inline unsigned short Dictionary::toBaseLowerCase(unsigned short c) { - if (c < sizeof(BASE_CHARS) / sizeof(BASE_CHARS[0])) { - c = BASE_CHARS[c]; - } - if (c >='A' && c <= 'Z') { - c |= 32; - } else if (c > 127) { - c = latin_tolower(c); - } - return c; -} - } // namespace latinime #endif // LATINIME_DICTIONARY_H diff --git a/native/src/proximity_info.cpp b/native/src/proximity_info.cpp index 763a3a174..b6bab2274 100644 --- a/native/src/proximity_info.cpp +++ b/native/src/proximity_info.cpp @@ -47,12 +47,12 @@ ProximityInfo::ProximityInfo(const int maxProximityCharsSize, const int keyboard HAS_TOUCH_POSITION_CORRECTION_DATA(keyCount > 0 && keyXCoordinates && keyYCoordinates && keyWidths && keyHeights && keyCharCodes && sweetSpotCenterXs && sweetSpotCenterYs && sweetSpotRadii), - mInputXCoordinates(NULL), mInputYCoordinates(NULL), + mInputXCoordinates(0), mInputYCoordinates(0), mTouchPositionCorrectionEnabled(false) { const int proximityGridLength = GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE; mProximityCharsArray = new uint32_t[proximityGridLength]; if (DEBUG_PROXIMITY_INFO) { - LOGI("Create proximity info array %d", proximityGridLength); + AKLOGI("Create proximity info array %d", proximityGridLength); } memcpy(mProximityCharsArray, proximityCharsArray, proximityGridLength * sizeof(mProximityCharsArray[0])); @@ -100,13 +100,21 @@ inline int ProximityInfo::getStartIndexFromCoordinates(const int x, const int y) } bool ProximityInfo::hasSpaceProximity(const int x, const int y) const { + if (x < 0 || y < 0) { + if (DEBUG_DICT) { + AKLOGI("HasSpaceProximity: Illegal coordinates (%d, %d)", x, y); + assert(false); + } + return false; + } + const int startIndex = getStartIndexFromCoordinates(x, y); if (DEBUG_PROXIMITY_INFO) { - LOGI("hasSpaceProximity: index %d", startIndex); + AKLOGI("hasSpaceProximity: index %d, %d, %d", startIndex, x, y); } for (int i = 0; i < MAX_PROXIMITY_CHARS_SIZE; ++i) { if (DEBUG_PROXIMITY_INFO) { - LOGI("Index: %d", mProximityCharsArray[startIndex + i]); + AKLOGI("Index: %d", mProximityCharsArray[startIndex + i]); } if (mProximityCharsArray[startIndex + i] == KEYCODE_SPACE) { return true; @@ -157,6 +165,9 @@ float ProximityInfo::calculateNormalizedSquaredDistance( if (!hasSweetSpotData(keyIndex)) { return NOT_A_DISTANCE_FLOAT; } + if (NOT_A_COORDINATE == mInputXCoordinates[inputIndex]) { + return NOT_A_DISTANCE_FLOAT; + } const float squaredDistance = calculateSquaredDistanceFromSweetSpotCenter(keyIndex, inputIndex); const float squaredRadius = square(mSweetSpotRadii[keyIndex]); return squaredDistance / squaredRadius; @@ -167,7 +178,7 @@ int ProximityInfo::getKeyIndex(const int c) const { // We do not have the coordinate data return NOT_A_INDEX; } - const unsigned short baseLowerC = Dictionary::toBaseLowerCase(c); + const unsigned short baseLowerC = toBaseLowerCase(c); if (baseLowerC > MAX_CHAR_CODE) { return NOT_A_INDEX; } @@ -232,7 +243,7 @@ ProximityInfo::ProximityType ProximityInfo::getMatchedProximityId(const int inde const unsigned short c, const bool checkProximityChars, int *proximityIndex) const { const int *currentChars = getProximityCharsAt(index); const int firstChar = currentChars[0]; - const unsigned short baseLowerC = Dictionary::toBaseLowerCase(c); + const unsigned short baseLowerC = toBaseLowerCase(c); // The first char in the array is what user typed. If it matches right away, // that means the user typed that same char for this pos. @@ -245,12 +256,13 @@ ProximityInfo::ProximityType ProximityInfo::getMatchedProximityId(const int inde // If the non-accented, lowercased version of that first character matches c, // then we have a non-accented version of the accented character the user // typed. Treat it as a close char. - if (Dictionary::toBaseLowerCase(firstChar) == baseLowerC) + if (toBaseLowerCase(firstChar) == baseLowerC) return NEAR_PROXIMITY_CHAR; // Not an exact nor an accent-alike match: search the list of close keys int j = 1; - while (j < MAX_PROXIMITY_CHARS_SIZE && currentChars[j] > 0) { + while (j < MAX_PROXIMITY_CHARS_SIZE + && currentChars[j] > ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) { const bool matched = (currentChars[j] == baseLowerC || currentChars[j] == c); if (matched) { if (proximityIndex) { @@ -260,6 +272,21 @@ ProximityInfo::ProximityType ProximityInfo::getMatchedProximityId(const int inde } ++j; } + if (j < MAX_PROXIMITY_CHARS_SIZE + && currentChars[j] == ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) { + ++j; + while (j < MAX_PROXIMITY_CHARS_SIZE + && currentChars[j] > ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) { + const bool matched = (currentChars[j] == baseLowerC || currentChars[j] == c); + if (matched) { + if (proximityIndex) { + *proximityIndex = j; + } + return ADDITIONAL_PROXIMITY_CHAR; + } + ++j; + } + } // Was not included, signal this as an unrelated character. return UNRELATED_CHAR; diff --git a/native/src/proximity_info.h b/native/src/proximity_info.h index 35e354c6e..b77c1bb0a 100644 --- a/native/src/proximity_info.h +++ b/native/src/proximity_info.h @@ -26,7 +26,7 @@ namespace latinime { class Correction; class ProximityInfo { -public: + public: static const int NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2 = 10; static const int NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR = 1 << NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2; @@ -38,7 +38,9 @@ public: // It is a char located nearby on the keyboard NEAR_PROXIMITY_CHAR, // It is an unrelated char - UNRELATED_CHAR + UNRELATED_CHAR, + // Additional proximity char which can differ by language. + ADDITIONAL_PROXIMITY_CHAR } ProximityType; ProximityInfo(const int maxProximityCharsSize, const int keyboardWidth, @@ -56,7 +58,7 @@ public: bool existsCharInProximityAt(const int index, const int c) const; bool existsAdjacentProximityChars(const int index) const; ProximityType getMatchedProximityId(const int index, const unsigned short c, - const bool checkProximityChars, int *proximityIndex = NULL) const; + const bool checkProximityChars, int *proximityIndex = 0) const; int getNormalizedSquaredDistance(const int inputIndex, const int proximityIndex) const { return mNormalizedSquaredDistances[inputIndex * MAX_PROXIMITY_CHARS_SIZE + proximityIndex]; } @@ -68,7 +70,7 @@ public: return mTouchPositionCorrectionEnabled; } -private: + private: // The max number of the keys in one keyboard layout static const int MAX_KEY_COUNT_IN_A_KEYBOARD = 64; // The upper limit of the char code in mCodeToKeyIndex diff --git a/native/src/terminal_attributes.h b/native/src/terminal_attributes.h new file mode 100644 index 000000000..1f9815936 --- /dev/null +++ b/native/src/terminal_attributes.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef LATINIME_TERMINAL_ATTRIBUTES_H +#define LATINIME_TERMINAL_ATTRIBUTES_H + +#include "unigram_dictionary.h" + +namespace latinime { + +/** + * This class encapsulates information about a terminal that allows to + * retrieve local node attributes like the list of shortcuts without + * exposing the format structure to the client. + */ +class TerminalAttributes { + public: + class ShortcutIterator { + const uint8_t* const mDict; + bool mHasNextShortcutTarget; + int mPos; + + public: + ShortcutIterator(const uint8_t* dict, const int pos, const uint8_t flags) : mDict(dict), + mPos(pos) { + mHasNextShortcutTarget = (0 != (flags & UnigramDictionary::FLAG_HAS_SHORTCUT_TARGETS)); + } + + inline bool hasNextShortcutTarget() const { + return mHasNextShortcutTarget; + } + + // Gets the shortcut target itself as a uint16_t string. For parameters and return value + // see BinaryFormat::getWordAtAddress. + inline int getNextShortcutTarget(const int maxDepth, uint16_t* outWord) { + const int shortcutFlags = BinaryFormat::getFlagsAndForwardPointer(mDict, &mPos); + mHasNextShortcutTarget = + 0 != (shortcutFlags & UnigramDictionary::FLAG_ATTRIBUTE_HAS_NEXT); + int shortcutAddress = + BinaryFormat::getAttributeAddressAndForwardPointer(mDict, shortcutFlags, &mPos); + return BinaryFormat::getWordAtAddress(mDict, shortcutAddress, maxDepth, outWord); + } + }; + + private: + const uint8_t* const mDict; + const uint8_t mFlags; + const int mStartPos; + + public: + TerminalAttributes(const uint8_t* const dict, const uint8_t flags, const int pos) : + mDict(dict), mFlags(flags), mStartPos(pos) { + } + + inline bool isShortcutOnly() const { + return 0 != (mFlags & UnigramDictionary::FLAG_IS_SHORTCUT_ONLY); + } + + inline ShortcutIterator getShortcutIterator() const { + return ShortcutIterator(mDict, mStartPos, mFlags); + } +}; +} // namespace latinime + +#endif // LATINIME_TERMINAL_ATTRIBUTES_H diff --git a/native/src/unigram_dictionary.cpp b/native/src/unigram_dictionary.cpp index 8eb5a9700..155bdcb7a 100644 --- a/native/src/unigram_dictionary.cpp +++ b/native/src/unigram_dictionary.cpp @@ -25,6 +25,7 @@ #include "unigram_dictionary.h" #include "binary_format.h" +#include "terminal_attributes.h" namespace latinime { @@ -46,21 +47,25 @@ UnigramDictionary::UnigramDictionary(const uint8_t* const streamStart, int typed BYTES_IN_ONE_CHAR(MAX_PROXIMITY_CHARS * sizeof(int)), MAX_UMLAUT_SEARCH_DEPTH(DEFAULT_MAX_UMLAUT_SEARCH_DEPTH) { if (DEBUG_DICT) { - LOGI("UnigramDictionary - constructor"); + AKLOGI("UnigramDictionary - constructor"); } - mCorrection = new Correction(typedLetterMultiplier, fullWordMultiplier); } UnigramDictionary::~UnigramDictionary() { - delete mCorrection; } -static inline unsigned int getCodesBufferSize(const int* codes, const int codesSize, +static inline unsigned int getCodesBufferSize(const int *codes, const int codesSize, const int MAX_PROXIMITY_CHARS) { return sizeof(*codes) * MAX_PROXIMITY_CHARS * codesSize; } -bool UnigramDictionary::isDigraph(const int* codes, const int i, const int codesSize) const { +// TODO: This needs to take an const unsigned short* and not tinker with its contents +static inline void addWord( + unsigned short *word, int length, int frequency, WordsPriorityQueue *queue) { + queue->push(frequency, word, length); +} + +bool UnigramDictionary::isDigraph(const int *codes, const int i, const int codesSize) const { // There can't be a digraph if we don't have at least 2 characters to examine if (i + 2 > codesSize) return false; @@ -86,9 +91,10 @@ bool UnigramDictionary::isDigraph(const int* codes, const int i, const int codes // codesSrc is the current point in the user-input, original, content-unmodified buffer. // codesRemain is the remaining size in codesSrc. void UnigramDictionary::getWordWithDigraphSuggestionsRec(ProximityInfo *proximityInfo, - const int *xcoordinates, const int* ycoordinates, const int *codesBuffer, - const int codesBufferSize, const int flags, const int* codesSrc, const int codesRemain, - const int currentDepth, int* codesDest, unsigned short* outWords, int* frequencies) { + const int *xcoordinates, const int *ycoordinates, const int *codesBuffer, + const int codesBufferSize, const int flags, const int *codesSrc, + const int codesRemain, const int currentDepth, int *codesDest, Correction *correction, + WordsPriorityQueuePool *queuePool) { if (currentDepth < MAX_UMLAUT_SEARCH_DEPTH) { for (int i = 0; i < codesRemain; ++i) { @@ -105,8 +111,8 @@ void UnigramDictionary::getWordWithDigraphSuggestionsRec(ProximityInfo *proximit getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates, codesBuffer, codesBufferSize, flags, codesSrc + (i + 1) * MAX_PROXIMITY_CHARS, codesRemain - i - 1, - currentDepth + 1, codesDest + i * MAX_PROXIMITY_CHARS, outWords, - frequencies); + currentDepth + 1, codesDest + i * MAX_PROXIMITY_CHARS, correction, + queuePool); // Copy the second char of the digraph in place, then continue processing on // the remaining part of the word. @@ -114,9 +120,9 @@ void UnigramDictionary::getWordWithDigraphSuggestionsRec(ProximityInfo *proximit memcpy(codesDest + i * MAX_PROXIMITY_CHARS, codesSrc + i * MAX_PROXIMITY_CHARS, BYTES_IN_ONE_CHAR); getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates, - codesBuffer, codesBufferSize, flags, codesSrc + i * MAX_PROXIMITY_CHARS, - codesRemain - i, currentDepth + 1, codesDest + i * MAX_PROXIMITY_CHARS, - outWords, frequencies); + codesBuffer, codesBufferSize, flags, + codesSrc + i * MAX_PROXIMITY_CHARS, codesRemain - i, currentDepth + 1, + codesDest + i * MAX_PROXIMITY_CHARS, correction, queuePool); return; } } @@ -132,41 +138,47 @@ void UnigramDictionary::getWordWithDigraphSuggestionsRec(ProximityInfo *proximit memcpy(codesDest, codesSrc, remainingBytes); getWordSuggestions(proximityInfo, xcoordinates, ycoordinates, codesBuffer, - (codesDest - codesBuffer) / MAX_PROXIMITY_CHARS + codesRemain, outWords, frequencies, - flags); + (codesDest - codesBuffer) / MAX_PROXIMITY_CHARS + codesRemain, flags, correction, + queuePool); } -int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates, +int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo, + WordsPriorityQueuePool *queuePool, Correction *correction, const int *xcoordinates, const int *ycoordinates, const int *codes, const int codesSize, const int flags, unsigned short *outWords, int *frequencies) { + Correction* masterCorrection = correction; if (REQUIRES_GERMAN_UMLAUT_PROCESSING & flags) { // Incrementally tune the word and try all possibilities int codesBuffer[getCodesBufferSize(codes, codesSize, MAX_PROXIMITY_CHARS)]; getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates, codesBuffer, - codesSize, flags, codes, codesSize, 0, codesBuffer, outWords, frequencies); + codesSize, flags, codes, codesSize, 0, codesBuffer, masterCorrection, queuePool); } else { // Normal processing - getWordSuggestions(proximityInfo, xcoordinates, ycoordinates, codes, codesSize, - outWords, frequencies, flags); + getWordSuggestions(proximityInfo, xcoordinates, ycoordinates, codes, codesSize, flags, + masterCorrection, queuePool); } PROF_START(20); - // Get the word count - int suggestedWordsCount = 0; - while (suggestedWordsCount < MAX_WORDS && mFrequencies[suggestedWordsCount] > 0) { - suggestedWordsCount++; + if (DEBUG_DICT) { + double ns = queuePool->getMasterQueue()->getHighestNormalizedScore( + proximityInfo->getPrimaryInputWord(), codesSize, 0, 0, 0); + ns += 0; + AKLOGI("Max normalized score = %f", ns); } + const int suggestedWordsCount = + queuePool->getMasterQueue()->outputSuggestions(frequencies, outWords); if (DEBUG_DICT) { - LOGI("Returning %d words", suggestedWordsCount); + double ns = queuePool->getMasterQueue()->getHighestNormalizedScore( + proximityInfo->getPrimaryInputWord(), codesSize, 0, 0, 0); + ns += 0; + AKLOGI("Returning %d words", suggestedWordsCount); /// Print the returned words for (int j = 0; j < suggestedWordsCount; ++j) { -#ifdef FLAG_DBG - short unsigned int* w = mOutputChars + j * MAX_WORD_LENGTH; + short unsigned int* w = outWords + j * MAX_WORD_LENGTH; char s[MAX_WORD_LENGTH]; for (int i = 0; i <= MAX_WORD_LENGTH; i++) s[i] = w[i]; - LOGI("%s %i", s, mFrequencies[j]); -#endif + AKLOGI("%s %i", s, frequencies[j]); } } PROF_END(20); @@ -175,23 +187,19 @@ int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo, const int *x } void UnigramDictionary::getWordSuggestions(ProximityInfo *proximityInfo, - const int *xcoordinates, const int *ycoordinates, const int *codes, const int codesSize, - unsigned short *outWords, int *frequencies, const int flags) { + const int *xcoordinates, const int *ycoordinates, const int *codes, + const int inputLength, const int flags, Correction *correction, + WordsPriorityQueuePool *queuePool) { PROF_OPEN; PROF_START(0); - initSuggestions( - proximityInfo, xcoordinates, ycoordinates, codes, codesSize, outWords, frequencies); - if (DEBUG_DICT) assert(codesSize == mInputLength); - - const int maxDepth = min(mInputLength * MAX_DEPTH_MULTIPLIER, MAX_WORD_LENGTH); - mCorrection->initCorrection(mProximityInfo, mInputLength, maxDepth); + queuePool->clearAll(); PROF_END(0); - const bool useFullEditDistance = USE_FULL_EDIT_DISTANCE & flags; - // TODO: remove PROF_START(1); - getSuggestionCandidates(useFullEditDistance); + const bool useFullEditDistance = USE_FULL_EDIT_DISTANCE & flags; + getOneWordSuggestions(proximityInfo, xcoordinates, ycoordinates, codes, useFullEditDistance, + inputLength, correction, queuePool); PROF_END(1); PROF_START(2); @@ -203,250 +211,369 @@ void UnigramDictionary::getWordSuggestions(ProximityInfo *proximityInfo, PROF_END(3); PROF_START(4); - // Note: This line is intentionally left blank + bool hasAutoCorrectionCandidate = false; + WordsPriorityQueue* masterQueue = queuePool->getMasterQueue(); + if (masterQueue->size() > 0) { + double nsForMaster = masterQueue->getHighestNormalizedScore( + proximityInfo->getPrimaryInputWord(), inputLength, 0, 0, 0); + hasAutoCorrectionCandidate = (nsForMaster > START_TWO_WORDS_CORRECTION_THRESHOLD); + } PROF_END(4); PROF_START(5); - // Suggestions with missing space - if (SUGGEST_WORDS_WITH_MISSING_SPACE_CHARACTER - && mInputLength >= MIN_USER_TYPED_LENGTH_FOR_MISSING_SPACE_SUGGESTION) { - for (int i = 1; i < codesSize; ++i) { - if (DEBUG_DICT) { - LOGI("--- Suggest missing space characters %d", i); - } - getMissingSpaceWords(mInputLength, i, mCorrection, useFullEditDistance); - } + // Multiple word suggestions + if (SUGGEST_MULTIPLE_WORDS + && inputLength >= MIN_USER_TYPED_LENGTH_FOR_MULTIPLE_WORD_SUGGESTION) { + getSplitMultipleWordsSuggestions(proximityInfo, xcoordinates, ycoordinates, codes, + useFullEditDistance, inputLength, correction, queuePool, + hasAutoCorrectionCandidate); } PROF_END(5); PROF_START(6); - if (SUGGEST_WORDS_WITH_SPACE_PROXIMITY && proximityInfo) { - // The first and last "mistyped spaces" are taken care of by excessive character handling - for (int i = 1; i < codesSize - 1; ++i) { - if (DEBUG_DICT) { - LOGI("--- Suggest words with proximity space %d", i); - } - const int x = xcoordinates[i]; - const int y = ycoordinates[i]; - if (DEBUG_PROXIMITY_INFO) { - LOGI("Input[%d] x = %d, y = %d, has space proximity = %d", - i, x, y, proximityInfo->hasSpaceProximity(x, y)); - } - if (proximityInfo->hasSpaceProximity(x, y)) { - getMistypedSpaceWords(mInputLength, i, mCorrection, useFullEditDistance); + // Note: This line is intentionally left blank + PROF_END(6); + + if (DEBUG_DICT) { + queuePool->dumpSubQueue1TopSuggestions(); + for (int i = 0; i < SUB_QUEUE_MAX_COUNT; ++i) { + WordsPriorityQueue* queue = queuePool->getSubQueue(FIRST_WORD_INDEX, i); + if (queue->size() > 0) { + WordsPriorityQueue::SuggestedWord* sw = queue->top(); + const int score = sw->mScore; + const unsigned short* word = sw->mWord; + const int wordLength = sw->mWordLength; + double ns = Correction::RankingAlgorithm::calcNormalizedScore( + proximityInfo->getPrimaryInputWord(), i, word, wordLength, score); + ns += 0; + AKLOGI("--- TOP SUB WORDS for %d --- %d %f [%d]", i, score, ns, + (ns > TWO_WORDS_CORRECTION_WITH_OTHER_ERROR_THRESHOLD)); + DUMP_WORD(proximityInfo->getPrimaryInputWord(), i); + DUMP_WORD(word, wordLength); } } } - PROF_END(6); } void UnigramDictionary::initSuggestions(ProximityInfo *proximityInfo, const int *xCoordinates, - const int *yCoordinates, const int *codes, const int codesSize, - unsigned short *outWords, int *frequencies) { + const int *yCoordinates, const int *codes, const int inputLength, Correction *correction) { if (DEBUG_DICT) { - LOGI("initSuggest"); - } - mFrequencies = frequencies; - mOutputChars = outWords; - mInputLength = codesSize; - proximityInfo->setInputParams(codes, codesSize, xCoordinates, yCoordinates); - mProximityInfo = proximityInfo; -} - -static inline void registerNextLetter(unsigned short c, int *nextLetters, int nextLettersSize) { - if (c < nextLettersSize) { - nextLetters[c]++; + AKLOGI("initSuggest"); } -} - -// TODO: We need to optimize addWord by using STL or something -// TODO: This needs to take an const unsigned short* and not tinker with its contents -bool UnigramDictionary::addWord(unsigned short *word, int length, int frequency) { - word[length] = 0; - if (DEBUG_DICT && DEBUG_SHOW_FOUND_WORD) { -#ifdef FLAG_DBG - char s[length + 1]; - for (int i = 0; i <= length; i++) s[i] = word[i]; - LOGI("Found word = %s, freq = %d", s, frequency); -#endif - } - if (length > MAX_WORD_LENGTH) { - if (DEBUG_DICT) { - LOGI("Exceeded max word length."); - } - return false; - } - - // Find the right insertion point - int insertAt = 0; - while (insertAt < MAX_WORDS) { - // TODO: How should we sort words with the same frequency? - if (frequency > mFrequencies[insertAt]) { - break; - } - insertAt++; - } - if (insertAt < MAX_WORDS) { - if (DEBUG_DICT) { -#ifdef FLAG_DBG - char s[length + 1]; - for (int i = 0; i <= length; i++) s[i] = word[i]; - LOGI("Added word = %s, freq = %d, %d", s, frequency, S_INT_MAX); -#endif - } - memmove((char*) mFrequencies + (insertAt + 1) * sizeof(mFrequencies[0]), - (char*) mFrequencies + insertAt * sizeof(mFrequencies[0]), - (MAX_WORDS - insertAt - 1) * sizeof(mFrequencies[0])); - mFrequencies[insertAt] = frequency; - memmove((char*) mOutputChars + (insertAt + 1) * MAX_WORD_LENGTH * sizeof(short), - (char*) mOutputChars + insertAt * MAX_WORD_LENGTH * sizeof(short), - (MAX_WORDS - insertAt - 1) * sizeof(short) * MAX_WORD_LENGTH); - unsigned short *dest = mOutputChars + insertAt * MAX_WORD_LENGTH; - while (length--) { - *dest++ = *word++; - } - *dest = 0; // NULL terminate - if (DEBUG_DICT) { - LOGI("Added word at %d", insertAt); - } - return true; - } - return false; + proximityInfo->setInputParams(codes, inputLength, xCoordinates, yCoordinates); + const int maxDepth = min(inputLength * MAX_DEPTH_MULTIPLIER, MAX_WORD_LENGTH); + correction->initCorrection(proximityInfo, inputLength, maxDepth); } static const char QUOTE = '\''; static const char SPACE = ' '; -void UnigramDictionary::getSuggestionCandidates(const bool useFullEditDistance) { +void UnigramDictionary::getOneWordSuggestions(ProximityInfo *proximityInfo, + const int *xcoordinates, const int *ycoordinates, const int *codes, + const bool useFullEditDistance, const int inputLength, Correction *correction, + WordsPriorityQueuePool *queuePool) { + initSuggestions(proximityInfo, xcoordinates, ycoordinates, codes, inputLength, correction); + getSuggestionCandidates(useFullEditDistance, inputLength, correction, queuePool, + true /* doAutoCompletion */, DEFAULT_MAX_ERRORS, FIRST_WORD_INDEX); +} + +void UnigramDictionary::getSuggestionCandidates(const bool useFullEditDistance, + const int inputLength, Correction *correction, WordsPriorityQueuePool *queuePool, + const bool doAutoCompletion, const int maxErrors, const int currentWordIndex) { // TODO: Remove setCorrectionParams - mCorrection->setCorrectionParams(0, 0, 0, - -1 /* spaceProximityPos */, -1 /* missingSpacePos */, useFullEditDistance); + correction->setCorrectionParams(0, 0, 0, + -1 /* spaceProximityPos */, -1 /* missingSpacePos */, useFullEditDistance, + doAutoCompletion, maxErrors); int rootPosition = ROOT_POS; // Get the number of children of root, then increment the position - int childCount = Dictionary::getCount(DICT_ROOT, &rootPosition); + int childCount = BinaryFormat::getGroupCountAndForwardPointer(DICT_ROOT, &rootPosition); int outputIndex = 0; - mCorrection->initCorrectionState(rootPosition, childCount, (mInputLength <= 0)); + correction->initCorrectionState(rootPosition, childCount, (inputLength <= 0)); // Depth first search while (outputIndex >= 0) { - if (mCorrection->initProcessState(outputIndex)) { - int siblingPos = mCorrection->getTreeSiblingPos(outputIndex); + if (correction->initProcessState(outputIndex)) { + int siblingPos = correction->getTreeSiblingPos(outputIndex); int firstChildPos; const bool needsToTraverseChildrenNodes = processCurrentNode(siblingPos, - mCorrection, &childCount, &firstChildPos, &siblingPos); + correction, &childCount, &firstChildPos, &siblingPos, queuePool, + currentWordIndex); // Update next sibling pos - mCorrection->setTreeSiblingPos(outputIndex, siblingPos); + correction->setTreeSiblingPos(outputIndex, siblingPos); if (needsToTraverseChildrenNodes) { // Goes to child node - outputIndex = mCorrection->goDownTree(outputIndex, childCount, firstChildPos); + outputIndex = correction->goDownTree(outputIndex, childCount, firstChildPos); } } else { // Goes to parent sibling node - outputIndex = mCorrection->getTreeParentIndex(outputIndex); + outputIndex = correction->getTreeParentIndex(outputIndex); } } } -void UnigramDictionary::getMissingSpaceWords( - const int inputLength, const int missingSpacePos, Correction *correction, - const bool useFullEditDistance) { - correction->setCorrectionParams(-1 /* skipPos */, -1 /* excessivePos */, - -1 /* transposedPos */, -1 /* spaceProximityPos */, missingSpacePos, - useFullEditDistance); - getSplitTwoWordsSuggestion(inputLength, correction); -} - -void UnigramDictionary::getMistypedSpaceWords( - const int inputLength, const int spaceProximityPos, Correction *correction, - const bool useFullEditDistance) { - correction->setCorrectionParams(-1 /* skipPos */, -1 /* excessivePos */, - -1 /* transposedPos */, spaceProximityPos, -1 /* missingSpacePos */, - useFullEditDistance); - getSplitTwoWordsSuggestion(inputLength, correction); -} - -inline bool UnigramDictionary::needsToSkipCurrentNode(const unsigned short c, - const int inputIndex, const int skipPos, const int depth) { - const unsigned short userTypedChar = mProximityInfo->getPrimaryCharAt(inputIndex); - // Skip the ' or other letter and continue deeper - return (c == QUOTE && userTypedChar != QUOTE) || skipPos == depth; -} +inline void UnigramDictionary::onTerminal(const int freq, + const TerminalAttributes& terminalAttributes, Correction *correction, + WordsPriorityQueuePool *queuePool, const bool addToMasterQueue, + const int currentWordIndex) { + const int inputIndex = correction->getInputIndex(); + const bool addToSubQueue = inputIndex < SUB_QUEUE_MAX_COUNT; -inline void UnigramDictionary::onTerminal(const int freq, Correction *correction) { int wordLength; unsigned short* wordPointer; - const int finalFreq = correction->getFinalFreq(freq, &wordPointer, &wordLength); - if (finalFreq >= 0) { - addWord(wordPointer, wordLength, finalFreq); + + if ((currentWordIndex == FIRST_WORD_INDEX) && addToMasterQueue) { + WordsPriorityQueue *masterQueue = queuePool->getMasterQueue(); + const int finalFreq = correction->getFinalFreq(freq, &wordPointer, &wordLength); + if (finalFreq != NOT_A_FREQUENCY) { + if (!terminalAttributes.isShortcutOnly()) { + addWord(wordPointer, wordLength, finalFreq, masterQueue); + } + + // Please note that the shortcut candidates will be added to the master queue only. + TerminalAttributes::ShortcutIterator iterator = + terminalAttributes.getShortcutIterator(); + while (iterator.hasNextShortcutTarget()) { + // TODO: addWord only supports weak ordering, meaning we have no means + // to control the order of the shortcuts relative to one another or to the word. + // We need to either modulate the frequency of each shortcut according + // to its own shortcut frequency or to make the queue + // so that the insert order is protected inside the queue for words + // with the same score. + uint16_t shortcutTarget[MAX_WORD_LENGTH_INTERNAL]; + const int shortcutTargetStringLength = iterator.getNextShortcutTarget( + MAX_WORD_LENGTH_INTERNAL, shortcutTarget); + addWord(shortcutTarget, shortcutTargetStringLength, finalFreq, masterQueue); + } + } + } + + // We only allow two words + other error correction for words with SUB_QUEUE_MIN_WORD_LENGTH + // or more length. + if (inputIndex >= SUB_QUEUE_MIN_WORD_LENGTH && addToSubQueue) { + WordsPriorityQueue *subQueue; + subQueue = queuePool->getSubQueue(currentWordIndex, inputIndex); + if (!subQueue) { + return; + } + const int finalFreq = correction->getFinalFreqForSubQueue(freq, &wordPointer, &wordLength, + inputIndex); + addWord(wordPointer, wordLength, finalFreq, subQueue); } } -void UnigramDictionary::getSplitTwoWordsSuggestion( - const int inputLength, Correction* correction) { - const int spaceProximityPos = correction->getSpaceProximityPos(); - const int missingSpacePos = correction->getMissingSpacePos(); +bool UnigramDictionary::getSubStringSuggestion( + ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates, + const int *codes, const bool useFullEditDistance, Correction *correction, + WordsPriorityQueuePool* queuePool, const int inputLength, + const bool hasAutoCorrectionCandidate, const int currentWordIndex, + const int inputWordStartPos, const int inputWordLength, + const int outputWordStartPos, const bool isSpaceProximity, int *freqArray, + int*wordLengthArray, unsigned short* outputWord, int *outputWordLength) { + unsigned short* tempOutputWord = 0; + int nextWordLength = 0; + // TODO: Optimize init suggestion + initSuggestions(proximityInfo, xcoordinates, ycoordinates, codes, + inputLength, correction); + + int freq = getMostFrequentWordLike( + inputWordStartPos, inputWordLength, proximityInfo, mWord); + if (freq > 0) { + nextWordLength = inputWordLength; + tempOutputWord = mWord; + } else if (!hasAutoCorrectionCandidate) { + if (inputWordStartPos > 0) { + const int offset = inputWordStartPos; + initSuggestions(proximityInfo, &xcoordinates[offset], &ycoordinates[offset], + codes + offset * MAX_PROXIMITY_CHARS, inputWordLength, correction); + queuePool->clearSubQueue(currentWordIndex); + getSuggestionCandidates(useFullEditDistance, inputWordLength, correction, + queuePool, false, MAX_ERRORS_FOR_TWO_WORDS, currentWordIndex); + if (DEBUG_DICT) { + if (currentWordIndex < MULTIPLE_WORDS_SUGGESTION_MAX_WORDS) { + AKLOGI("Dump word candidates(%d) %d", currentWordIndex, inputWordLength); + for (int i = 0; i < SUB_QUEUE_MAX_COUNT; ++i) { + queuePool->getSubQueue(currentWordIndex, i)->dumpTopWord(); + } + } + } + } + WordsPriorityQueue* queue = queuePool->getSubQueue(currentWordIndex, inputWordLength); + if (!queue || queue->size() < 1) { + return false; + } + int score = 0; + const double ns = queue->getHighestNormalizedScore( + proximityInfo->getPrimaryInputWord(), inputWordLength, + &tempOutputWord, &score, &nextWordLength); + if (DEBUG_DICT) { + AKLOGI("NS(%d) = %f, Score = %d", currentWordIndex, ns, score); + } + // Two words correction won't be done if the score of the first word doesn't exceed the + // threshold. + if (ns < TWO_WORDS_CORRECTION_WITH_OTHER_ERROR_THRESHOLD + || nextWordLength < SUB_QUEUE_MIN_WORD_LENGTH) { + return false; + } + freq = score >> (nextWordLength + TWO_WORDS_PLUS_OTHER_ERROR_CORRECTION_DEMOTION_DIVIDER); + } if (DEBUG_DICT) { - int inputCount = 0; - if (spaceProximityPos >= 0) ++inputCount; - if (missingSpacePos >= 0) ++inputCount; - assert(inputCount <= 1); + AKLOGI("Freq(%d): %d, length: %d, input length: %d, input start: %d (%d)" + , currentWordIndex, freq, nextWordLength, inputWordLength, inputWordStartPos, + wordLengthArray[0]); + } + if (freq <= 0 || nextWordLength <= 0 + || MAX_WORD_LENGTH <= (outputWordStartPos + nextWordLength)) { + return false; + } + for (int i = 0; i < nextWordLength; ++i) { + outputWord[outputWordStartPos + i] = tempOutputWord[i]; } - const bool isSpaceProximity = spaceProximityPos >= 0; - const int firstWordStartPos = 0; - const int secondWordStartPos = isSpaceProximity ? (spaceProximityPos + 1) : missingSpacePos; - const int firstWordLength = isSpaceProximity ? spaceProximityPos : missingSpacePos; - const int secondWordLength = isSpaceProximity - ? (inputLength - spaceProximityPos - 1) - : (inputLength - missingSpacePos); - - if (inputLength >= MAX_WORD_LENGTH) return; - if (0 >= firstWordLength || 0 >= secondWordLength || firstWordStartPos >= secondWordStartPos - || firstWordStartPos < 0 || secondWordStartPos + secondWordLength > inputLength) - return; - const int newWordLength = firstWordLength + secondWordLength + 1; - // Allocating variable length array on stack - unsigned short word[newWordLength]; - const int firstFreq = getMostFrequentWordLike(firstWordStartPos, firstWordLength, mWord); - if (DEBUG_DICT) { - LOGI("First freq: %d", firstFreq); + // Put output values + freqArray[currentWordIndex] = freq; + // TODO: put output length instead of input length + wordLengthArray[currentWordIndex] = inputWordLength; + const int tempOutputWordLength = outputWordStartPos + nextWordLength; + if (outputWordLength) { + *outputWordLength = tempOutputWordLength; } - if (firstFreq <= 0) return; - for (int i = 0; i < firstWordLength; ++i) { - word[i] = mWord[i]; + if ((inputWordStartPos + inputWordLength) < inputLength) { + if (outputWordStartPos + nextWordLength >= MAX_WORD_LENGTH) { + return false; + } + outputWord[tempOutputWordLength] = SPACE; + if (outputWordLength) { + ++*outputWordLength; + } + } else if (currentWordIndex >= 1) { + // TODO: Handle 3 or more words + const int pairFreq = correction->getFreqForSplitMultipleWords( + freqArray, wordLengthArray, currentWordIndex + 1, isSpaceProximity, outputWord); + if (DEBUG_DICT) { + DUMP_WORD(outputWord, tempOutputWordLength); + AKLOGI("Split two words: %d, %d, %d, %d, (%d) %d", freqArray[0], freqArray[1], pairFreq, + inputLength, wordLengthArray[0], tempOutputWordLength); + } + addWord(outputWord, tempOutputWordLength, pairFreq, queuePool->getMasterQueue()); } + return true; +} - const int secondFreq = getMostFrequentWordLike(secondWordStartPos, secondWordLength, mWord); - if (DEBUG_DICT) { - LOGI("Second freq: %d", secondFreq); +void UnigramDictionary::getMultiWordsSuggestionRec(ProximityInfo *proximityInfo, + const int *xcoordinates, const int *ycoordinates, const int *codes, + const bool useFullEditDistance, const int inputLength, + Correction *correction, WordsPriorityQueuePool* queuePool, + const bool hasAutoCorrectionCandidate, const int startInputPos, const int startWordIndex, + const int outputWordLength, int *freqArray, int* wordLengthArray, + unsigned short* outputWord) { + if (startWordIndex >= (MULTIPLE_WORDS_SUGGESTION_MAX_WORDS - 1)) { + // Return if the last word index + return; } - if (secondFreq <= 0) return; + if (startWordIndex >= 1 + && (hasAutoCorrectionCandidate + || inputLength < MIN_INPUT_LENGTH_FOR_THREE_OR_MORE_WORDS_CORRECTION)) { + // Do not suggest 3+ words if already has auto correction candidate + return; + } + for (int i = startInputPos + 1; i < inputLength; ++i) { + if (DEBUG_CORRECTION_FREQ) { + AKLOGI("Multi words(%d), start in %d sep %d start out %d", + startWordIndex, startInputPos, i, outputWordLength); + DUMP_WORD(outputWord, outputWordLength); + } + int tempOutputWordLength = 0; + // Current word + int inputWordStartPos = startInputPos; + int inputWordLength = i - startInputPos; + if (!getSubStringSuggestion(proximityInfo, xcoordinates, ycoordinates, codes, + useFullEditDistance, correction, queuePool, inputLength, hasAutoCorrectionCandidate, + startWordIndex, inputWordStartPos, inputWordLength, outputWordLength, + true /* not used */, freqArray, wordLengthArray, outputWord, + &tempOutputWordLength)) { + continue; + } + + if (DEBUG_CORRECTION_FREQ) { + AKLOGI("Do missing space correction"); + } + // Next word + // Missing space + inputWordStartPos = i; + inputWordLength = inputLength - i; + if(!getSubStringSuggestion(proximityInfo, xcoordinates, ycoordinates, codes, + useFullEditDistance, correction, queuePool, inputLength, hasAutoCorrectionCandidate, + startWordIndex + 1, inputWordStartPos, inputWordLength, tempOutputWordLength, + false /* missing space */, freqArray, wordLengthArray, outputWord, 0)) { + getMultiWordsSuggestionRec(proximityInfo, xcoordinates, ycoordinates, codes, + useFullEditDistance, inputLength, correction, queuePool, + hasAutoCorrectionCandidate, inputWordStartPos, startWordIndex + 1, + tempOutputWordLength, freqArray, wordLengthArray, outputWord); + } - word[firstWordLength] = SPACE; - for (int i = (firstWordLength + 1); i < newWordLength; ++i) { - word[i] = mWord[i - firstWordLength - 1]; + // Mistyped space + ++inputWordStartPos; + --inputWordLength; + + if (inputWordLength <= 0) { + continue; + } + + const int x = xcoordinates[inputWordStartPos - 1]; + const int y = ycoordinates[inputWordStartPos - 1]; + if (!proximityInfo->hasSpaceProximity(x, y)) { + continue; + } + + if (DEBUG_CORRECTION_FREQ) { + AKLOGI("Do mistyped space correction"); + } + getSubStringSuggestion(proximityInfo, xcoordinates, ycoordinates, codes, + useFullEditDistance, correction, queuePool, inputLength, hasAutoCorrectionCandidate, + startWordIndex + 1, inputWordStartPos, inputWordLength, tempOutputWordLength, + true /* mistyped space */, freqArray, wordLengthArray, outputWord, 0); } +} - const int pairFreq = mCorrection->getFreqForSplitTwoWords(firstFreq, secondFreq, word); +void UnigramDictionary::getSplitMultipleWordsSuggestions(ProximityInfo *proximityInfo, + const int *xcoordinates, const int *ycoordinates, const int *codes, + const bool useFullEditDistance, const int inputLength, + Correction *correction, WordsPriorityQueuePool* queuePool, + const bool hasAutoCorrectionCandidate) { + if (inputLength >= MAX_WORD_LENGTH) return; + if (DEBUG_DICT) { + // MAX_PROXIMITY_CHARS_SIZE in ProximityInfo.java should be 16 + assert(MAX_PROXIMITY_CHARS == 16); + } if (DEBUG_DICT) { - LOGI("Split two words: %d, %d, %d, %d", firstFreq, secondFreq, pairFreq, inputLength); + AKLOGI("--- Suggest multiple words"); } - addWord(word, newWordLength, pairFreq); - return; + + // Allocating fixed length array on stack + unsigned short outputWord[MAX_WORD_LENGTH]; + int freqArray[MULTIPLE_WORDS_SUGGESTION_MAX_WORDS]; + int wordLengthArray[MULTIPLE_WORDS_SUGGESTION_MAX_WORDS]; + const int outputWordLength = 0; + const int startInputPos = 0; + const int startWordIndex = 0; + getMultiWordsSuggestionRec(proximityInfo, xcoordinates, ycoordinates, codes, + useFullEditDistance, inputLength, correction, queuePool, hasAutoCorrectionCandidate, + startInputPos, startWordIndex, outputWordLength, freqArray, wordLengthArray, + outputWord); } // Wrapper for getMostFrequentWordLikeInner, which matches it to the previous // interface. inline int UnigramDictionary::getMostFrequentWordLike(const int startInputIndex, - const int inputLength, unsigned short *word) { + const int inputLength, ProximityInfo *proximityInfo, unsigned short *word) { uint16_t inWord[inputLength]; for (int i = 0; i < inputLength; ++i) { - inWord[i] = (uint16_t)mProximityInfo->getPrimaryCharAt(startInputIndex + i); + inWord[i] = (uint16_t)proximityInfo->getPrimaryCharAt(startInputIndex + i); } return getMostFrequentWordLikeInner(inWord, inputLength, word); } @@ -470,8 +597,8 @@ static inline bool testCharGroupForContinuedLikeness(const uint8_t flags, const bool hasMultipleChars = (0 != (UnigramDictionary::FLAG_HAS_MULTIPLE_CHARS & flags)); int pos = startPos; int32_t character = BinaryFormat::getCharCodeAndForwardPointer(root, &pos); - int32_t baseChar = Dictionary::toBaseLowerCase(character); - const uint16_t wChar = Dictionary::toBaseLowerCase(inWord[startInputIndex]); + int32_t baseChar = toBaseLowerCase(character); + const uint16_t wChar = toBaseLowerCase(inWord[startInputIndex]); if (baseChar != wChar) { *outPos = hasMultipleChars ? BinaryFormat::skipOtherCharacters(root, pos) : pos; @@ -483,8 +610,8 @@ static inline bool testCharGroupForContinuedLikeness(const uint8_t flags, if (hasMultipleChars) { character = BinaryFormat::getCharCodeAndForwardPointer(root, &pos); while (NOT_A_CHARACTER != character) { - baseChar = Dictionary::toBaseLowerCase(character); - if (Dictionary::toBaseLowerCase(inWord[++inputIndex]) != baseChar) { + baseChar = toBaseLowerCase(character); + if (toBaseLowerCase(inWord[++inputIndex]) != baseChar) { *outPos = BinaryFormat::skipOtherCharacters(root, pos); *outInputIndex = startInputIndex; return false; @@ -521,9 +648,10 @@ int UnigramDictionary::getMostFrequentWordLikeInner(const uint16_t * const inWor int maxFreq = -1; const uint8_t* const root = DICT_ROOT; - mStackChildCount[0] = root[0]; + int startPos = 0; + mStackChildCount[0] = BinaryFormat::getGroupCountAndForwardPointer(root, &startPos); mStackInputIndex[0] = 0; - mStackSiblingPos[0] = 1; + mStackSiblingPos[0] = startPos; while (depth >= 0) { const int charGroupCount = mStackChildCount[depth]; int pos = mStackSiblingPos[depth]; @@ -597,7 +725,8 @@ int UnigramDictionary::getBigramPosition(int pos, unsigned short *word, int offs // given level, as output into newCount when traversing this level's parent. inline bool UnigramDictionary::processCurrentNode(const int initialPos, Correction *correction, int *newCount, - int *newChildrenPosition, int *nextSiblingPosition) { + int *newChildrenPosition, int *nextSiblingPosition, WordsPriorityQueuePool *queuePool, + const int currentWordIndex) { if (DEBUG_DICT) { correction->checkState(); } @@ -648,7 +777,7 @@ inline bool UnigramDictionary::processCurrentNode(const int initialPos, if (stateType == Correction::TRAVERSE_ALL_ON_TERMINAL || stateType == Correction::ON_TERMINAL) { needsToInvokeOnTerminal = true; - } else if (stateType == Correction::UNRELATED) { + } else if (stateType == Correction::UNRELATED || correction->needsToPrune()) { // We found that this is an unrelated character, so we should give up traversing // this node and its children entirely. // However we may not be on the last virtual node yet so we skip the remaining @@ -672,12 +801,14 @@ inline bool UnigramDictionary::processCurrentNode(const int initialPos, } while (NOT_A_CHARACTER != c); if (isTerminalNode) { - if (needsToInvokeOnTerminal) { - // The frequency should be here, because we come here only if this is actually - // a terminal node, and we are on its last char. - const int freq = BinaryFormat::readFrequencyWithoutMovingPointer(DICT_ROOT, pos); - onTerminal(freq, mCorrection); - } + // The frequency should be here, because we come here only if this is actually + // a terminal node, and we are on its last char. + const int freq = BinaryFormat::readFrequencyWithoutMovingPointer(DICT_ROOT, pos); + const int childrenAddressPos = BinaryFormat::skipFrequency(flags, pos); + const int attributesPos = BinaryFormat::skipChildrenPosition(flags, childrenAddressPos); + TerminalAttributes terminalAttributes(DICT_ROOT, flags, attributesPos); + onTerminal(freq, terminalAttributes, correction, queuePool, needsToInvokeOnTerminal, + currentWordIndex); // If there are more chars in this node, then this virtual node has children. // If we are on the last char, this virtual node has children if this node has. @@ -702,7 +833,7 @@ inline bool UnigramDictionary::processCurrentNode(const int initialPos, *nextSiblingPosition = BinaryFormat::skipChildrenPosAndAttributes(DICT_ROOT, flags, pos); if (DEBUG_DICT_FULL) { - LOGI("Traversing was pruned."); + AKLOGI("Traversing was pruned."); } return false; } diff --git a/native/src/unigram_dictionary.h b/native/src/unigram_dictionary.h index ef9709a89..396a81149 100644 --- a/native/src/unigram_dictionary.h +++ b/native/src/unigram_dictionary.h @@ -22,17 +22,14 @@ #include "correction_state.h" #include "defines.h" #include "proximity_info.h" - -#ifndef NULL -#define NULL 0 -#endif +#include "words_priority_queue.h" +#include "words_priority_queue_pool.h" namespace latinime { +class TerminalAttributes; class UnigramDictionary { - -public: - + public: // Mask and flags for children address type selection. static const int MASK_GROUP_ADDRESS_TYPE = 0xC0; static const int FLAG_GROUP_ADDRESS_TYPE_NOADDRESS = 0x00; @@ -46,8 +43,14 @@ public: // Flag for terminal groups static const int FLAG_IS_TERMINAL = 0x10; + // Flag for shortcut targets presence + static const int FLAG_HAS_SHORTCUT_TARGETS = 0x08; // Flag for bigram presence static const int FLAG_HAS_BIGRAMS = 0x04; + // Flag for shortcut-only words. Some words are shortcut-only, which means they match when + // the user types them but they don't pop in the suggestion strip, only the words they are + // shortcuts for do. + static const int FLAG_IS_SHORTCUT_ONLY = 0x02; // Attribute (bigram/shortcut) related flags: // Flag for presence of more attributes @@ -64,47 +67,73 @@ public: static const int FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES = 0x20; static const int FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES = 0x30; + // Error tolerances + static const int DEFAULT_MAX_ERRORS = 2; + static const int MAX_ERRORS_FOR_TWO_WORDS = 1; + UnigramDictionary(const uint8_t* const streamStart, int typedLetterMultipler, int fullWordMultiplier, int maxWordLength, int maxWords, int maxProximityChars, const bool isLatestDictVersion); bool isValidWord(const uint16_t* const inWord, const int length) const; int getBigramPosition(int pos, unsigned short *word, int offset, int length) const; - int getSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates, + int getSuggestions(ProximityInfo *proximityInfo, WordsPriorityQueuePool *queuePool, + Correction *correction, const int *xcoordinates, const int *ycoordinates, const int *codes, const int codesSize, const int flags, unsigned short *outWords, int *frequencies); virtual ~UnigramDictionary(); -private: - + private: void getWordSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates, - const int *ycoordinates, const int *codes, const int codesSize, - unsigned short *outWords, int *frequencies, const int flags); - bool isDigraph(const int* codes, const int i, const int codesSize) const; + const int *ycoordinates, const int *codes, const int inputLength, + const int flags, Correction *correction, WordsPriorityQueuePool *queuePool); + bool isDigraph(const int *codes, const int i, const int codesSize) const; void getWordWithDigraphSuggestionsRec(ProximityInfo *proximityInfo, const int *xcoordinates, const int* ycoordinates, const int *codesBuffer, - const int codesBufferSize, const int flags, const int* codesSrc, const int codesRemain, - const int currentDepth, int* codesDest, unsigned short* outWords, int* frequencies); + const int codesBufferSize, const int flags, const int* codesSrc, + const int codesRemain, const int currentDepth, int* codesDest, Correction *correction, + WordsPriorityQueuePool* queuePool); void initSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates, - const int *ycoordinates, const int *codes, const int codesSize, - unsigned short *outWords, int *frequencies); - void getSuggestionCandidates(const bool useFullEditDistance); - bool addWord(unsigned short *word, int length, int frequency); - void getSplitTwoWordsSuggestion(const int inputLength, Correction *correction); - void getMissingSpaceWords(const int inputLength, const int missingSpacePos, - Correction *correction, const bool useFullEditDistance); - void getMistypedSpaceWords(const int inputLength, const int spaceProximityPos, - Correction *correction, const bool useFullEditDistance); - void onTerminal(const int freq, Correction *correction); + const int *ycoordinates, const int *codes, const int codesSize, Correction *correction); + void getOneWordSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates, + const int *ycoordinates, const int *codes, const bool useFullEditDistance, + const int inputLength, Correction *correction, WordsPriorityQueuePool* queuePool); + void getSuggestionCandidates( + const bool useFullEditDistance, const int inputLength, Correction *correction, + WordsPriorityQueuePool* queuePool, const bool doAutoCompletion, const int maxErrors, + const int currentWordIndex); + void getSplitMultipleWordsSuggestions(ProximityInfo *proximityInfo, + const int *xcoordinates, const int *ycoordinates, const int *codes, + const bool useFullEditDistance, const int inputLength, + Correction *correction, WordsPriorityQueuePool* queuePool, + const bool hasAutoCorrectionCandidate); + void onTerminal(const int freq, const TerminalAttributes& terminalAttributes, + Correction *correction, WordsPriorityQueuePool *queuePool, const bool addToMasterQueue, + const int currentWordIndex); bool needsToSkipCurrentNode(const unsigned short c, const int inputIndex, const int skipPos, const int depth); // Process a node by considering proximity, missing and excessive character - bool processCurrentNode(const int initialPos, - Correction *correction, int *newCount, - int *newChildPosition, int *nextSiblingPosition); + bool processCurrentNode(const int initialPos, Correction *correction, int *newCount, + int *newChildPosition, int *nextSiblingPosition, WordsPriorityQueuePool *queuePool, + const int currentWordIndex); int getMostFrequentWordLike(const int startInputIndex, const int inputLength, - unsigned short *word); + ProximityInfo *proximityInfo, unsigned short *word); int getMostFrequentWordLikeInner(const uint16_t* const inWord, const int length, - short unsigned int* outWord); + short unsigned int *outWord); + bool getSubStringSuggestion( + ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates, + const int *codes, const bool useFullEditDistance, Correction *correction, + WordsPriorityQueuePool* queuePool, const int inputLength, + const bool hasAutoCorrectionCandidate, const int currentWordIndex, + const int inputWordStartPos, const int inputWordLength, + const int outputWordStartPos, const bool isSpaceProximity, int *freqArray, + int *wordLengthArray, unsigned short* outputWord, int *outputWordLength); + void getMultiWordsSuggestionRec(ProximityInfo *proximityInfo, + const int *xcoordinates, const int *ycoordinates, const int *codes, + const bool useFullEditDistance, const int inputLength, + Correction *correction, WordsPriorityQueuePool* queuePool, + const bool hasAutoCorrectionCandidate, const int startPos, const int startWordIndex, + const int outputWordLength, int *freqArray, int* wordLengthArray, + unsigned short* outputWord); const uint8_t* const DICT_ROOT; const int MAX_WORD_LENGTH; @@ -127,14 +156,8 @@ private: }; static const struct digraph_t { int first; int second; } GERMAN_UMLAUT_DIGRAPHS[]; - int *mFrequencies; - unsigned short *mOutputChars; - ProximityInfo *mProximityInfo; - Correction *mCorrection; - int mInputLength; - // MAX_WORD_LENGTH_INTERNAL must be bigger than MAX_WORD_LENGTH - unsigned short mWord[MAX_WORD_LENGTH_INTERNAL]; - + // Still bundled members + unsigned short mWord[MAX_WORD_LENGTH_INTERNAL];// TODO: remove int mStackChildCount[MAX_WORD_LENGTH_INTERNAL];// TODO: remove int mStackInputIndex[MAX_WORD_LENGTH_INTERNAL];// TODO: remove int mStackSiblingPos[MAX_WORD_LENGTH_INTERNAL];// TODO: remove diff --git a/native/src/words_priority_queue.h b/native/src/words_priority_queue.h new file mode 100644 index 000000000..249962eec --- /dev/null +++ b/native/src/words_priority_queue.h @@ -0,0 +1,195 @@ +/* + * 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. + */ + +#ifndef LATINIME_WORDS_PRIORITY_QUEUE_H +#define LATINIME_WORDS_PRIORITY_QUEUE_H + +#include <cstring> // for memcpy() +#include <iostream> +#include <queue> +#include "defines.h" + +namespace latinime { + +class WordsPriorityQueue { + public: + class SuggestedWord { + public: + int mScore; + unsigned short mWord[MAX_WORD_LENGTH_INTERNAL]; + int mWordLength; + bool mUsed; + + void setParams(int score, unsigned short* word, int wordLength) { + mScore = score; + mWordLength = wordLength; + memcpy(mWord, word, sizeof(unsigned short) * wordLength); + mUsed = true; + } + }; + + WordsPriorityQueue(int maxWords, int maxWordLength) : + MAX_WORDS((unsigned int) maxWords), MAX_WORD_LENGTH( + (unsigned int) maxWordLength) { + mSuggestedWords = new SuggestedWord[maxWordLength]; + for (int i = 0; i < maxWordLength; ++i) { + mSuggestedWords[i].mUsed = false; + } + mHighestSuggestedWord = 0; + } + + ~WordsPriorityQueue() { + delete[] mSuggestedWords; + } + + void push(int score, unsigned short* word, int wordLength) { + SuggestedWord* sw = 0; + if (mSuggestions.size() >= MAX_WORDS) { + sw = mSuggestions.top(); + const int minScore = sw->mScore; + if (minScore >= score) { + return; + } else { + sw->mUsed = false; + mSuggestions.pop(); + } + } + if (sw == 0) { + sw = getFreeSuggestedWord(score, word, wordLength); + } else { + sw->setParams(score, word, wordLength); + } + if (sw == 0) { + AKLOGE("SuggestedWord is accidentally null."); + return; + } + if (DEBUG_WORDS_PRIORITY_QUEUE) { + AKLOGI("Push word. %d, %d", score, wordLength); + DUMP_WORD(word, wordLength); + } + mSuggestions.push(sw); + if (!mHighestSuggestedWord || mHighestSuggestedWord->mScore < sw->mScore) { + mHighestSuggestedWord = sw; + } + } + + SuggestedWord* top() { + if (mSuggestions.empty()) return 0; + SuggestedWord* sw = mSuggestions.top(); + return sw; + } + + int outputSuggestions(int *frequencies, unsigned short *outputChars) { + mHighestSuggestedWord = 0; + const unsigned int size = min( + MAX_WORDS, static_cast<unsigned int>(mSuggestions.size())); + int index = size - 1; + while (!mSuggestions.empty() && index >= 0) { + SuggestedWord* sw = mSuggestions.top(); + if (DEBUG_WORDS_PRIORITY_QUEUE) { + AKLOGI("dump word. %d", sw->mScore); + DUMP_WORD(sw->mWord, sw->mWordLength); + } + const unsigned int wordLength = sw->mWordLength; + char* targetAdr = (char*) outputChars + + (index) * MAX_WORD_LENGTH * sizeof(short); + frequencies[index] = sw->mScore; + memcpy(targetAdr, sw->mWord, (wordLength) * sizeof(short)); + if (wordLength < MAX_WORD_LENGTH) { + ((unsigned short*) targetAdr)[wordLength] = 0; + } + sw->mUsed = false; + mSuggestions.pop(); + --index; + } + return size; + } + + int size() const { + return mSuggestions.size(); + } + + void clear() { + mHighestSuggestedWord = 0; + while (!mSuggestions.empty()) { + SuggestedWord* sw = mSuggestions.top(); + if (DEBUG_WORDS_PRIORITY_QUEUE) { + AKLOGI("Clear word. %d", sw->mScore); + DUMP_WORD(sw->mWord, sw->mWordLength); + } + sw->mUsed = false; + mSuggestions.pop(); + } + } + + void dumpTopWord() { + if (size() <= 0) { + return; + } + DUMP_WORD(mHighestSuggestedWord->mWord, mHighestSuggestedWord->mWordLength); + } + + double getHighestNormalizedScore(const unsigned short* before, const int beforeLength, + unsigned short** outWord, int *outScore, int *outLength) { + if (!mHighestSuggestedWord) { + return 0.0; + } + SuggestedWord* sw = mHighestSuggestedWord; + const int score = sw->mScore; + unsigned short* word = sw->mWord; + const int wordLength = sw->mWordLength; + if (outScore) { + *outScore = score; + } + if (outWord) { + *outWord = word; + } + if (outLength) { + *outLength = wordLength; + } + return Correction::RankingAlgorithm::calcNormalizedScore( + before, beforeLength, word, wordLength, score); + } + + private: + struct wordComparator { + bool operator ()(SuggestedWord * left, SuggestedWord * right) { + return left->mScore > right->mScore; + } + }; + + SuggestedWord* getFreeSuggestedWord(int score, unsigned short* word, + int wordLength) { + for (unsigned int i = 0; i < MAX_WORD_LENGTH; ++i) { + if (!mSuggestedWords[i].mUsed) { + mSuggestedWords[i].setParams(score, word, wordLength); + return &mSuggestedWords[i]; + } + } + return 0; + } + + typedef std::priority_queue<SuggestedWord*, std::vector<SuggestedWord*>, + wordComparator> Suggestions; + Suggestions mSuggestions; + const unsigned int MAX_WORDS; + const unsigned int MAX_WORD_LENGTH; + SuggestedWord* mSuggestedWords; + SuggestedWord* mHighestSuggestedWord; +}; +} + +#endif // LATINIME_WORDS_PRIORITY_QUEUE_H diff --git a/native/src/words_priority_queue_pool.h b/native/src/words_priority_queue_pool.h new file mode 100644 index 000000000..5b50e8f4f --- /dev/null +++ b/native/src/words_priority_queue_pool.h @@ -0,0 +1,90 @@ +/* + * 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. + */ + +#ifndef LATINIME_WORDS_PRIORITY_QUEUE_POOL_H +#define LATINIME_WORDS_PRIORITY_QUEUE_POOL_H + +#include <assert.h> +#include <new> +#include "words_priority_queue.h" + +namespace latinime { + +class WordsPriorityQueuePool { + public: + WordsPriorityQueuePool(int mainQueueMaxWords, int subQueueMaxWords, int maxWordLength) { + mMasterQueue = new(mMasterQueueBuf) WordsPriorityQueue(mainQueueMaxWords, maxWordLength); + for (int i = 0, subQueueBufOffset = 0; + i < MULTIPLE_WORDS_SUGGESTION_MAX_WORDS * SUB_QUEUE_MAX_COUNT; + ++i, subQueueBufOffset += sizeof(WordsPriorityQueue)) { + mSubQueues[i] = new(mSubQueueBuf + subQueueBufOffset) + WordsPriorityQueue(subQueueMaxWords, maxWordLength); + } + } + + virtual ~WordsPriorityQueuePool() { + } + + WordsPriorityQueue* getMasterQueue() { + return mMasterQueue; + } + + WordsPriorityQueue* getSubQueue(const int wordIndex, const int inputWordLength) { + if (wordIndex >= MULTIPLE_WORDS_SUGGESTION_MAX_WORDS) { + return 0; + } + if (inputWordLength < 0 || inputWordLength >= SUB_QUEUE_MAX_COUNT) { + if (DEBUG_WORDS_PRIORITY_QUEUE) { + assert(false); + } + return 0; + } + return mSubQueues[wordIndex * SUB_QUEUE_MAX_COUNT + inputWordLength]; + } + + inline void clearAll() { + mMasterQueue->clear(); + for (int i = 0; i < MULTIPLE_WORDS_SUGGESTION_MAX_WORDS; ++i) { + clearSubQueue(i); + } + } + + inline void clearSubQueue(const int wordIndex) { + for (int i = 0; i < SUB_QUEUE_MAX_COUNT; ++i) { + WordsPriorityQueue* queue = getSubQueue(wordIndex, i); + if (queue) { + queue->clear(); + } + } + } + + void dumpSubQueue1TopSuggestions() { + AKLOGI("DUMP SUBQUEUE1 TOP SUGGESTIONS"); + for (int i = 0; i < SUB_QUEUE_MAX_COUNT; ++i) { + getSubQueue(0, i)->dumpTopWord(); + } + } + + private: + WordsPriorityQueue* mMasterQueue; + WordsPriorityQueue* mSubQueues[SUB_QUEUE_MAX_COUNT * MULTIPLE_WORDS_SUGGESTION_MAX_WORDS]; + char mMasterQueueBuf[sizeof(WordsPriorityQueue)]; + char mSubQueueBuf[MULTIPLE_WORDS_SUGGESTION_MAX_WORDS + * SUB_QUEUE_MAX_COUNT * sizeof(WordsPriorityQueue)]; +}; +} + +#endif // LATINIME_WORDS_PRIORITY_QUEUE_POOL_H diff --git a/tests/Android.mk b/tests/Android.mk index 658e8e294..6634070e9 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -1,3 +1,17 @@ +# 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. + LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml index 210e81489..38a2ecfeb 100644 --- a/tests/AndroidManifest.xml +++ b/tests/AndroidManifest.xml @@ -22,8 +22,6 @@ <application> <uses-library android:name="android.test.runner" /> <!-- meta-data android:name="com.android.contacts.iconset" android:resource="@xml/iconset" /--> - <uses-permission android:name="android.permission.READ_CONTACTS" /> - </application> <instrumentation android:name="android.test.InstrumentationTestRunner" diff --git a/tests/data/bigramlist.xml b/tests/data/bigramlist.xml index dd3f2916e..d3d8bb801 100644 --- a/tests/data/bigramlist.xml +++ b/tests/data/bigramlist.xml @@ -25,7 +25,7 @@ <bi w1="about" count="3"> <w w2="part" p="117" /> <w w2="business" p="100" /> - <w w2="being" p="10" /> + <w w2="being" p="90" /> </bi> <bi w1="business" count="1"> <w w2="people" p="100" /> diff --git a/tests/res/raw/test.dict b/tests/res/raw/test.dict Binary files differindex 6a5d6d794..453fc9fce 100644 --- a/tests/res/raw/test.dict +++ b/tests/res/raw/test.dict diff --git a/tests/res/values/donottranslate.xml b/tests/res/values/donottranslate.xml new file mode 100644 index 000000000..1ca4451d4 --- /dev/null +++ b/tests/res/values/donottranslate.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2012, 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> + <string name="empty_string">""</string> + <string name="single_char">"a"</string> + <string name="space">" "</string> + <string name="single_label">"abc"</string> + <string name="spaces">" "</string> + <string name="spaces_in_label">"a b c"</string> + <string name="spaces_at_beginning_of_label">" abc"</string> + <string name="spaces_at_end_of_label">"abc "</string> + <string name="label_surrounded_by_spaces">" abc "</string> + <string name="escaped_char">"\\a"</string> + <string name="escaped_comma">"\\,"</string> + <string name="escaped_comma_escape">"a\\,\\"</string> + <string name="escaped_escape">"\\\\"</string> + <string name="escaped_label">"a\\bc"</string> + <string name="escaped_label_at_beginning">"\\abc"</string> + <string name="escaped_label_at_end">"abc\\"</string> + <string name="escaped_label_with_comma">"a\\,c"</string> + <string name="escaped_label_with_comma_at_beginning">"\\,bc"</string> + <string name="escaped_label_with_comma_at_end">"ab\\,"</string> + <string name="escaped_label_with_successive">"\\,\\\\bc"</string> + <string name="escaped_label_with_escape">"a\\\\c"</string> + <string name="multiple_chars">"a,b,c"</string> + <string name="multiple_chars_surrounded_by_spaces">" a , b , c "</string> + <string name="multiple_labels">"abc,def,ghi"</string> + <string name="multiple_labels_surrounded_by_spaces">" abc , def , ghi "</string> + <string name="multiple_chars_with_comma">"a,\\,,c"</string> + <string name="multiple_chars_with_comma_surrounded_by_spaces">" a , \\, , c "</string> + <string name="multiple_labels_with_escape">"\\abc,d\\ef,gh\\i"</string> + <string name="multiple_labels_with_escape_surrounded_by_spaces">" \\abc , d\\ef , gh\\i "</string> + <string name="multiple_labels_with_comma_and_escape">"ab\\\\,d\\\\\\,,g\\,i"</string> + <string name="multiple_labels_with_comma_and_escape_surrounded_by_spaces">" ab\\\\ , d\\\\\\, , g\\,i "</string> + <string name="indirect_string">@string/multiple_chars</string> + <string name="indirect_string_with_literal">x,@string/multiple_chars,y</string> + <string name="infinite_indirection">infinite,@string/infinite_indirection,loop</string> +</resources> diff --git a/tests/src/com/android/inputmethod/keyboard/MiniKeyboardBuilderTests.java b/tests/src/com/android/inputmethod/keyboard/MiniKeyboardBuilderTests.java deleted file mode 100644 index a143bbad5..000000000 --- a/tests/src/com/android/inputmethod/keyboard/MiniKeyboardBuilderTests.java +++ /dev/null @@ -1,1416 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.keyboard; - -import com.android.inputmethod.keyboard.MiniKeyboard.Builder.MiniKeyboardParams; - -import android.test.AndroidTestCase; - -public class MiniKeyboardBuilderTests extends AndroidTestCase { - private static final int MAX_COLUMNS = 5; - private static final int WIDTH = 10; - private static final int HEIGHT = 10; - - private static final int KEYBOARD_WIDTH = WIDTH * 10; - private static final int XPOS_L0 = WIDTH * 0; - private static final int XPOS_L1 = WIDTH * 1; - private static final int XPOS_L2 = WIDTH * 2; - private static final int XPOS_M0 = WIDTH * 5; - private static final int XPOS_R3 = WIDTH * 6; - private static final int XPOS_R2 = WIDTH * 7; - private static final int XPOS_R1 = WIDTH * 8; - private static final int XPOS_R0 = WIDTH * 9; - - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - public void testLayoutError() { - MiniKeyboardParams params = null; - try { - params = new MiniKeyboardParams(10, MAX_COLUMNS + 1, WIDTH, HEIGHT, WIDTH * 2, - WIDTH * MAX_COLUMNS); - fail("Should throw IllegalArgumentException"); - } catch (IllegalArgumentException e) { - // Too small keyboard to hold mini keyboard. - } - assertNull("Too small keyboard to hold mini keyboard", params); - } - - // Mini keyboard layout test. - // "[n]" represents n-th key position in mini keyboard. - // "[1]" is the default key. - - // [1] - public void testLayout1KeyM0() { - MiniKeyboardParams params = new MiniKeyboardParams(1, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_M0, KEYBOARD_WIDTH); - assertEquals("1 key M0 columns", 1, params.mNumColumns); - assertEquals("1 key M0 rows", 1, params.mNumRows); - assertEquals("1 key M0 left", 0, params.mLeftKeys); - assertEquals("1 key M0 right", 1, params.mRightKeys); - assertEquals("1 key M0 [1]", 0, params.getColumnPos(0)); - assertEquals("1 key M0 adjust", 0, params.mTopRowAdjustment); - assertEquals("1 key M0 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |[1] - public void testLayout1KeyL0() { - MiniKeyboardParams params = new MiniKeyboardParams(1, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L0, KEYBOARD_WIDTH); - assertEquals("1 key L0 columns", 1, params.mNumColumns); - assertEquals("1 key L0 rows", 1, params.mNumRows); - assertEquals("1 key L0 left", 0, params.mLeftKeys); - assertEquals("1 key L0 right", 1, params.mRightKeys); - assertEquals("1 key L0 [1]", 0, params.getColumnPos(0)); - assertEquals("1 key L0 adjust", 0, params.mTopRowAdjustment); - assertEquals("1 key L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ [1] - public void testLayout1KeyL1() { - MiniKeyboardParams params = new MiniKeyboardParams(1, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L1, KEYBOARD_WIDTH); - assertEquals("1 key L1 columns", 1, params.mNumColumns); - assertEquals("1 key L1 rows", 1, params.mNumRows); - assertEquals("1 key L1 left", 0, params.mLeftKeys); - assertEquals("1 key L1 right", 1, params.mRightKeys); - assertEquals("1 key L1 [1]", 0, params.getColumnPos(0)); - assertEquals("1 key L1 adjust", 0, params.mTopRowAdjustment); - assertEquals("1 key L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ ___ [1] - public void testLayout1KeyL2() { - MiniKeyboardParams params = new MiniKeyboardParams(1, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L2, KEYBOARD_WIDTH); - assertEquals("1 key L2 columns", 1, params.mNumColumns); - assertEquals("1 key L2 rows", 1, params.mNumRows); - assertEquals("1 key L2 left", 0, params.mLeftKeys); - assertEquals("1 key L2 right", 1, params.mRightKeys); - assertEquals("1 key L2 [1]", 0, params.getColumnPos(0)); - assertEquals("1 key L2 adjust", 0, params.mTopRowAdjustment); - assertEquals("1 key L2 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // [1]| - public void testLayout1KeyR0() { - MiniKeyboardParams params = new MiniKeyboardParams(1, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R0, KEYBOARD_WIDTH); - assertEquals("1 key R0 columns", 1, params.mNumColumns); - assertEquals("1 key R0 rows", 1, params.mNumRows); - assertEquals("1 key R0 left", 0, params.mLeftKeys); - assertEquals("1 key R0 right", 1, params.mRightKeys); - assertEquals("1 key R0 [1]", 0, params.getColumnPos(0)); - assertEquals("1 key R0 adjust", 0, params.mTopRowAdjustment); - assertEquals("1 key R0 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // [1] ___| - public void testLayout1KeyR1() { - MiniKeyboardParams params = new MiniKeyboardParams(1, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R1, KEYBOARD_WIDTH); - assertEquals("1 key R1 columns", 1, params.mNumColumns); - assertEquals("1 key R1 rows", 1, params.mNumRows); - assertEquals("1 key R1 left", 0, params.mLeftKeys); - assertEquals("1 key R1 right", 1, params.mRightKeys); - assertEquals("1 key R1 [1]", 0, params.getColumnPos(0)); - assertEquals("1 key R1 adjust", 0, params.mTopRowAdjustment); - assertEquals("1 key R1 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // [1] ___ ___| - public void testLayout1KeyR2() { - MiniKeyboardParams params = new MiniKeyboardParams(1, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R2, KEYBOARD_WIDTH); - assertEquals("1 key R2 columns", 1, params.mNumColumns); - assertEquals("1 key R2 rows", 1, params.mNumRows); - assertEquals("1 key R2 left", 0, params.mLeftKeys); - assertEquals("1 key R2 right", 1, params.mRightKeys); - assertEquals("1 key R2 [1]", 0, params.getColumnPos(0)); - assertEquals("1 key R2 adjust", 0, params.mTopRowAdjustment); - assertEquals("1 key R2 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // [1] [2] - public void testLayout2KeyM0() { - MiniKeyboardParams params = new MiniKeyboardParams(2, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_M0, KEYBOARD_WIDTH); - assertEquals("2 key M0 columns", 2, params.mNumColumns); - assertEquals("2 key M0 rows", 1, params.mNumRows); - assertEquals("2 key M0 left", 0, params.mLeftKeys); - assertEquals("2 key M0 right", 2, params.mRightKeys); - assertEquals("2 key M0 [1]", 0, params.getColumnPos(0)); - assertEquals("2 key M0 [2]", 1, params.getColumnPos(1)); - assertEquals("2 key M0 adjust", 0, params.mTopRowAdjustment); - assertEquals("2 key M0 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |[1] [2] - public void testLayout2KeyL0() { - MiniKeyboardParams params = new MiniKeyboardParams(2, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L0, KEYBOARD_WIDTH); - assertEquals("2 key L0 columns", 2, params.mNumColumns); - assertEquals("2 key L0 rows", 1, params.mNumRows); - assertEquals("2 key L0 left", 0, params.mLeftKeys); - assertEquals("2 key L0 right", 2, params.mRightKeys); - assertEquals("2 key L0 [1]", 0, params.getColumnPos(0)); - assertEquals("2 key L0 [2]", 1, params.getColumnPos(1)); - assertEquals("2 key L0 adjust", 0, params.mTopRowAdjustment); - assertEquals("2 key L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ [1] [2] - public void testLayout2KeyL1() { - MiniKeyboardParams params = new MiniKeyboardParams(2, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L1, KEYBOARD_WIDTH); - assertEquals("2 key L1 columns", 2, params.mNumColumns); - assertEquals("2 key L1 rows", 1, params.mNumRows); - assertEquals("2 key L1 left", 0, params.mLeftKeys); - assertEquals("2 key L1 right", 2, params.mRightKeys); - assertEquals("2 key L1 [1]", 0, params.getColumnPos(0)); - assertEquals("2 key L1 [2]", 1, params.getColumnPos(1)); - assertEquals("2 key L1 adjust", 0, params.mTopRowAdjustment); - assertEquals("2 key L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ ___ [1] [2] - public void testLayout2KeyL2() { - MiniKeyboardParams params = new MiniKeyboardParams(2, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L2, KEYBOARD_WIDTH); - assertEquals("2 key L2 columns", 2, params.mNumColumns); - assertEquals("2 key L2 rows", 1, params.mNumRows); - assertEquals("2 key L2 left", 0, params.mLeftKeys); - assertEquals("2 key L2 right", 2, params.mRightKeys); - assertEquals("2 key L2 [1]", 0, params.getColumnPos(0)); - assertEquals("2 key L2 [2]", 1, params.getColumnPos(1)); - assertEquals("2 key L2 adjust", 0, params.mTopRowAdjustment); - assertEquals("2 key L2 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // [2] [1]| - public void testLayout2KeyR0() { - MiniKeyboardParams params = new MiniKeyboardParams(2, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R0, KEYBOARD_WIDTH); - assertEquals("2 key R0 columns", 2, params.mNumColumns); - assertEquals("2 key R0 rows", 1, params.mNumRows); - assertEquals("2 key R0 left", 1, params.mLeftKeys); - assertEquals("2 key R0 right", 1, params.mRightKeys); - assertEquals("2 key R0 [1]", 0, params.getColumnPos(0)); - assertEquals("2 key R0 [2]", -1, params.getColumnPos(1)); - assertEquals("2 key R0 adjust", 0, params.mTopRowAdjustment); - assertEquals("2 key R0 default", WIDTH * 1, params.getDefaultKeyCoordX()); - } - - // [2] [1] ___| - public void testLayout2KeyR1() { - MiniKeyboardParams params = new MiniKeyboardParams(2, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R1, KEYBOARD_WIDTH); - assertEquals("2 key R1 columns", 2, params.mNumColumns); - assertEquals("2 key R1 rows", 1, params.mNumRows); - assertEquals("2 key R1 left", 1, params.mLeftKeys); - assertEquals("2 key R1 right", 1, params.mRightKeys); - assertEquals("2 key R1 [1]", 0, params.getColumnPos(0)); - assertEquals("2 key R1 [2]", -1, params.getColumnPos(1)); - assertEquals("2 key R1 adjust", 0, params.mTopRowAdjustment); - assertEquals("2 key R1 default", WIDTH * 1, params.getDefaultKeyCoordX()); - } - - // [1] [2] ___ ___| - public void testLayout2KeyR2() { - MiniKeyboardParams params = new MiniKeyboardParams(2, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R2, KEYBOARD_WIDTH); - assertEquals("2 key R2 columns", 2, params.mNumColumns); - assertEquals("2 key R2 rows", 1, params.mNumRows); - assertEquals("2 key R2 left", 0, params.mLeftKeys); - assertEquals("2 key R2 right", 2, params.mRightKeys); - assertEquals("2 key R2 [1]", 0, params.getColumnPos(0)); - assertEquals("2 key R2 [2]", 1, params.getColumnPos(1)); - assertEquals("2 key R2 adjust", 0, params.mTopRowAdjustment); - assertEquals("2 key R2 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // [3] [1] [2] - public void testLayout3KeyM0() { - MiniKeyboardParams params = new MiniKeyboardParams(3, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_M0, KEYBOARD_WIDTH); - assertEquals("3 key columns", 3, params.mNumColumns); - assertEquals("3 key rows", 1, params.mNumRows); - assertEquals("3 key left", 1, params.mLeftKeys); - assertEquals("3 key right", 2, params.mRightKeys); - assertEquals("3 key [1]", 0, params.getColumnPos(0)); - assertEquals("3 key [2]", 1, params.getColumnPos(1)); - assertEquals("3 key [3]", -1, params.getColumnPos(2)); - assertEquals("3 key adjust", 0, params.mTopRowAdjustment); - assertEquals("3 key default", WIDTH * 1, params.getDefaultKeyCoordX()); - } - - // |[1] [2] [3] - public void testLayout3KeyL0() { - MiniKeyboardParams params = new MiniKeyboardParams(3, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L0, KEYBOARD_WIDTH); - assertEquals("3 key L0 columns", 3, params.mNumColumns); - assertEquals("3 key L0 rows", 1, params.mNumRows); - assertEquals("3 key L0 left", 0, params.mLeftKeys); - assertEquals("3 key L0 right", 3, params.mRightKeys); - assertEquals("3 key L0 [1]", 0, params.getColumnPos(0)); - assertEquals("3 key L0 [2]", 1, params.getColumnPos(1)); - assertEquals("3 key L0 [3]", 2, params.getColumnPos(2)); - assertEquals("3 key L0 adjust", 0, params.mTopRowAdjustment); - assertEquals("3 key L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ [1] [2] [3] - public void testLayout3KeyL1() { - MiniKeyboardParams params = new MiniKeyboardParams(3, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L1, KEYBOARD_WIDTH); - assertEquals("3 key L1 columns", 3, params.mNumColumns); - assertEquals("3 key L1 rows", 1, params.mNumRows); - assertEquals("3 key L1 left", 0, params.mLeftKeys); - assertEquals("3 key L1 right", 3, params.mRightKeys); - assertEquals("3 key L1 [1]", 0, params.getColumnPos(0)); - assertEquals("3 key L1 [2]", 1, params.getColumnPos(1)); - assertEquals("3 key L1 [3]", 2, params.getColumnPos(2)); - assertEquals("3 key L1 adjust", 0, params.mTopRowAdjustment); - assertEquals("3 key L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ ___ [3] [1] [2] - public void testLayout3KeyL2() { - MiniKeyboardParams params = new MiniKeyboardParams(3, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L2, KEYBOARD_WIDTH); - assertEquals("3 key L2 columns", 3, params.mNumColumns); - assertEquals("3 key L2 rows", 1, params.mNumRows); - assertEquals("3 key L2 left", 1, params.mLeftKeys); - assertEquals("3 key L2 right", 2, params.mRightKeys); - assertEquals("3 key L2 [1]", 0, params.getColumnPos(0)); - assertEquals("3 key L2 [2]", 1, params.getColumnPos(1)); - assertEquals("3 key L2 [3]", -1, params.getColumnPos(2)); - assertEquals("3 key L2 adjust", 0, params.mTopRowAdjustment); - assertEquals("3 key L2 default", WIDTH * 1, params.getDefaultKeyCoordX()); - } - - // [3] [2] [1]| - public void testLayout3KeyR0() { - MiniKeyboardParams params = new MiniKeyboardParams(3, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R0, KEYBOARD_WIDTH); - assertEquals("3 key R0 columns", 3, params.mNumColumns); - assertEquals("3 key R0 rows", 1, params.mNumRows); - assertEquals("3 key R0 left", 2, params.mLeftKeys); - assertEquals("3 key R0 right", 1, params.mRightKeys); - assertEquals("3 key R0 [1]", 0, params.getColumnPos(0)); - assertEquals("3 key R0 [2]", -1, params.getColumnPos(1)); - assertEquals("3 key R0 [3]", -2, params.getColumnPos(2)); - assertEquals("3 key R0 adjust", 0, params.mTopRowAdjustment); - assertEquals("3 key R0 default", WIDTH * 2, params.getDefaultKeyCoordX()); - } - - // [3] [2] [1] ___| - public void testLayout3KeyR1() { - MiniKeyboardParams params = new MiniKeyboardParams(3, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R1, KEYBOARD_WIDTH); - assertEquals("3 key R1 columns", 3, params.mNumColumns); - assertEquals("3 key R1 rows", 1, params.mNumRows); - assertEquals("3 key R1 left", 2, params.mLeftKeys); - assertEquals("3 key R1 right", 1, params.mRightKeys); - assertEquals("3 key R1 [1]", 0, params.getColumnPos(0)); - assertEquals("3 key R1 [2]", -1, params.getColumnPos(1)); - assertEquals("3 key R1 [3]", -2, params.getColumnPos(2)); - assertEquals("3 key R1 adjust", 0, params.mTopRowAdjustment); - assertEquals("3 key R1 default", WIDTH * 2, params.getDefaultKeyCoordX()); - } - - // [3] [1] [2] ___ ___| - public void testLayout3KeyR2() { - MiniKeyboardParams params = new MiniKeyboardParams(3, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R2, KEYBOARD_WIDTH); - assertEquals("3 key R2 columns", 3, params.mNumColumns); - assertEquals("3 key R2 rows", 1, params.mNumRows); - assertEquals("3 key R2 left", 1, params.mLeftKeys); - assertEquals("3 key R2 right", 2, params.mRightKeys); - assertEquals("3 key R2 [1]", 0, params.getColumnPos(0)); - assertEquals("3 key R2 [2]", 1, params.getColumnPos(1)); - assertEquals("3 key R2 [3]", -1, params.getColumnPos(2)); - assertEquals("3 key R2 adjust", 0, params.mTopRowAdjustment); - assertEquals("3 key R2 default", WIDTH * 1, params.getDefaultKeyCoordX()); - } - - // [3] [1] [2] [4] - public void testLayout4KeyM0() { - MiniKeyboardParams params = new MiniKeyboardParams(4, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_M0, KEYBOARD_WIDTH); - assertEquals("4 key columns", 4, params.mNumColumns); - assertEquals("4 key rows", 1, params.mNumRows); - assertEquals("4 key left", 1, params.mLeftKeys); - assertEquals("4 key right", 3, params.mRightKeys); - assertEquals("4 key [1]", 0, params.getColumnPos(0)); - assertEquals("4 key [2]", 1, params.getColumnPos(1)); - assertEquals("4 key [3]", -1, params.getColumnPos(2)); - assertEquals("4 key [4]", 2, params.getColumnPos(3)); - assertEquals("4 key adjust", 0, params.mTopRowAdjustment); - assertEquals("4 key default", WIDTH * 1, params.getDefaultKeyCoordX()); - } - - // |[1] [2] [3] [4] - public void testLayout4KeyL0() { - MiniKeyboardParams params = new MiniKeyboardParams(4, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L0, KEYBOARD_WIDTH); - assertEquals("4 key L0 columns", 4, params.mNumColumns); - assertEquals("4 key L0 rows", 1, params.mNumRows); - assertEquals("4 key L0 left", 0, params.mLeftKeys); - assertEquals("4 key L0 right", 4, params.mRightKeys); - assertEquals("4 key L0 [1]", 0, params.getColumnPos(0)); - assertEquals("4 key L0 [2]", 1, params.getColumnPos(1)); - assertEquals("4 key L0 [3]", 2, params.getColumnPos(2)); - assertEquals("4 key L0 [4]", 3, params.getColumnPos(3)); - assertEquals("4 key L0 adjust", 0, params.mTopRowAdjustment); - assertEquals("4 key L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ [1] [2] [3] [4] - public void testLayout4KeyL1() { - MiniKeyboardParams params = new MiniKeyboardParams(4, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L1, KEYBOARD_WIDTH); - assertEquals("4 key L1 columns", 4, params.mNumColumns); - assertEquals("4 key L1 rows", 1, params.mNumRows); - assertEquals("4 key L1 left", 0, params.mLeftKeys); - assertEquals("4 key L1 right", 4, params.mRightKeys); - assertEquals("4 key L1 [1]", 0, params.getColumnPos(0)); - assertEquals("4 key L1 [2]", 1, params.getColumnPos(1)); - assertEquals("4 key L1 [3]", 2, params.getColumnPos(2)); - assertEquals("4 key L1 [4]", 3, params.getColumnPos(3)); - assertEquals("4 key L1 adjust", 0, params.mTopRowAdjustment); - assertEquals("4 key L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ ___ [3] [1] [2] [4] - public void testLayout4KeyL2() { - MiniKeyboardParams params = new MiniKeyboardParams(4, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L2, KEYBOARD_WIDTH); - assertEquals("4 key L2 columns", 4, params.mNumColumns); - assertEquals("4 key L2 rows", 1, params.mNumRows); - assertEquals("4 key L2 left", 1, params.mLeftKeys); - assertEquals("4 key L2 right", 3, params.mRightKeys); - assertEquals("4 key L2 [1]", 0, params.getColumnPos(0)); - assertEquals("4 key L2 [2]", 1, params.getColumnPos(1)); - assertEquals("4 key L2 [3]", -1, params.getColumnPos(2)); - assertEquals("4 key L2 [4]", 2, params.getColumnPos(3)); - assertEquals("4 key L2 adjust", 0, params.mTopRowAdjustment); - assertEquals("4 key L2 default", WIDTH * 1, params.getDefaultKeyCoordX()); - } - - // [4] [3] [2] [1]| - public void testLayout4KeyR0() { - MiniKeyboardParams params = new MiniKeyboardParams(4, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R0, KEYBOARD_WIDTH); - assertEquals("4 key R0 columns", 4, params.mNumColumns); - assertEquals("4 key R0 rows", 1, params.mNumRows); - assertEquals("4 key R0 left", 3, params.mLeftKeys); - assertEquals("4 key R0 right", 1, params.mRightKeys); - assertEquals("4 key R0 [1]", 0, params.getColumnPos(0)); - assertEquals("4 key R0 [2]", -1, params.getColumnPos(1)); - assertEquals("4 key R0 [3]", -2, params.getColumnPos(2)); - assertEquals("4 key R0 [4]", -3, params.getColumnPos(3)); - assertEquals("4 key R0 adjust", 0, params.mTopRowAdjustment); - assertEquals("4 key R0 default", WIDTH * 3, params.getDefaultKeyCoordX()); - } - - // [4] [3] [2] [1] ___| - public void testLayout4KeyR1() { - MiniKeyboardParams params = new MiniKeyboardParams(4, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R1, KEYBOARD_WIDTH); - assertEquals("4 key R1 columns", 4, params.mNumColumns); - assertEquals("4 key R1 rows", 1, params.mNumRows); - assertEquals("4 key R1 left", 3, params.mLeftKeys); - assertEquals("4 key R1 right", 1, params.mRightKeys); - assertEquals("4 key R1 [1]", 0, params.getColumnPos(0)); - assertEquals("4 key R1 [2]", -1, params.getColumnPos(1)); - assertEquals("4 key R1 [3]", -2, params.getColumnPos(2)); - assertEquals("4 key R1 [4]", -3, params.getColumnPos(3)); - assertEquals("4 key R1 adjust", 0, params.mTopRowAdjustment); - assertEquals("4 key R1 default", WIDTH * 3, params.getDefaultKeyCoordX()); - } - - // [4] [3] [1] [2] ___ ___| - public void testLayout4KeyR2() { - MiniKeyboardParams params = new MiniKeyboardParams(4, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R2, KEYBOARD_WIDTH); - assertEquals("4 key R2 columns", 4, params.mNumColumns); - assertEquals("4 key R2 rows", 1, params.mNumRows); - assertEquals("4 key R2 left", 2, params.mLeftKeys); - assertEquals("4 key R2 right", 2, params.mRightKeys); - assertEquals("4 key R2 [1]", 0, params.getColumnPos(0)); - assertEquals("4 key R2 [2]", 1, params.getColumnPos(1)); - assertEquals("4 key R2 [3]", -1, params.getColumnPos(2)); - assertEquals("4 key R2 [4]", -2, params.getColumnPos(3)); - assertEquals("4 key R2 adjust", 0, params.mTopRowAdjustment); - assertEquals("4 key R2 default", WIDTH * 2, params.getDefaultKeyCoordX()); - } - - // [5] [3] [1] [2] [4] - public void testLayout5KeyM0() { - MiniKeyboardParams params = new MiniKeyboardParams(5, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_M0, KEYBOARD_WIDTH); - assertEquals("5 key columns", 5, params.mNumColumns); - assertEquals("5 key rows", 1, params.mNumRows); - assertEquals("5 key left", 2, params.mLeftKeys); - assertEquals("5 key right", 3, params.mRightKeys); - assertEquals("5 key [1]", 0, params.getColumnPos(0)); - assertEquals("5 key [2]", 1, params.getColumnPos(1)); - assertEquals("5 key [3]", -1, params.getColumnPos(2)); - assertEquals("5 key [4]", 2, params.getColumnPos(3)); - assertEquals("5 key [5]", -2, params.getColumnPos(4)); - assertEquals("5 key adjust", 0, params.mTopRowAdjustment); - assertEquals("5 key default", WIDTH * 2, params.getDefaultKeyCoordX()); - } - - // |[1] [2] [3] [4] [5] - public void testLayout5KeyL0() { - MiniKeyboardParams params = new MiniKeyboardParams(5, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L0, KEYBOARD_WIDTH); - assertEquals("5 key L0 columns", 5, params.mNumColumns); - assertEquals("5 key L0 rows", 1, params.mNumRows); - assertEquals("5 key L0 left", 0, params.mLeftKeys); - assertEquals("5 key L0 right", 5, params.mRightKeys); - assertEquals("5 key L0 [1]", 0, params.getColumnPos(0)); - assertEquals("5 key L0 [2]", 1, params.getColumnPos(1)); - assertEquals("5 key L0 [3]", 2, params.getColumnPos(2)); - assertEquals("5 key L0 [4]", 3, params.getColumnPos(3)); - assertEquals("5 key L0 [5]", 4, params.getColumnPos(4)); - assertEquals("5 key L0 adjust", 0, params.mTopRowAdjustment); - assertEquals("5 key L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ [1] [2] [3] [4] [5] - public void testLayout5KeyL1() { - MiniKeyboardParams params = new MiniKeyboardParams(5, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L1, KEYBOARD_WIDTH); - assertEquals("5 key L1 columns", 5, params.mNumColumns); - assertEquals("5 key L1 rows", 1, params.mNumRows); - assertEquals("5 key L1 left", 0, params.mLeftKeys); - assertEquals("5 key L1 right", 5, params.mRightKeys); - assertEquals("5 key L1 [1]", 0, params.getColumnPos(0)); - assertEquals("5 key L1 [2]", 1, params.getColumnPos(1)); - assertEquals("5 key L1 [3]", 2, params.getColumnPos(2)); - assertEquals("5 key L1 [4]", 3, params.getColumnPos(3)); - assertEquals("5 key L1 [5]", 4, params.getColumnPos(4)); - assertEquals("5 key L1 adjust", 0, params.mTopRowAdjustment); - assertEquals("5 key L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ ___ [3] [1] [2] [4] [5] - public void testLayout5KeyL2() { - MiniKeyboardParams params = new MiniKeyboardParams(5, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L2, KEYBOARD_WIDTH); - assertEquals("5 key L2 columns", 5, params.mNumColumns); - assertEquals("5 key L2 rows", 1, params.mNumRows); - assertEquals("5 key L2 left", 1, params.mLeftKeys); - assertEquals("5 key L2 right", 4, params.mRightKeys); - assertEquals("5 key L2 [1]", 0, params.getColumnPos(0)); - assertEquals("5 key L2 [2]", 1, params.getColumnPos(1)); - assertEquals("5 key L2 [3]", -1, params.getColumnPos(2)); - assertEquals("5 key L2 [4]", 2, params.getColumnPos(3)); - assertEquals("5 key L2 [5]", 3, params.getColumnPos(4)); - assertEquals("5 key L2 adjust", 0, params.mTopRowAdjustment); - assertEquals("5 key L2 default", WIDTH * 1, params.getDefaultKeyCoordX()); - } - - // [5] [4] [3] [2] [1]| - public void testLayout5KeyR0() { - MiniKeyboardParams params = new MiniKeyboardParams(5, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R0, KEYBOARD_WIDTH); - assertEquals("5 key R0 columns", 5, params.mNumColumns); - assertEquals("5 key R0 rows", 1, params.mNumRows); - assertEquals("5 key R0 left", 4, params.mLeftKeys); - assertEquals("5 key R0 right", 1, params.mRightKeys); - assertEquals("5 key R0 [1]", 0, params.getColumnPos(0)); - assertEquals("5 key R0 [2]", -1, params.getColumnPos(1)); - assertEquals("5 key R0 [3]", -2, params.getColumnPos(2)); - assertEquals("5 key R0 [4]", -3, params.getColumnPos(3)); - assertEquals("5 key R0 [5]", -4, params.getColumnPos(4)); - assertEquals("5 key R0 adjust", 0, params.mTopRowAdjustment); - assertEquals("5 key R0 default", WIDTH * 4, params.getDefaultKeyCoordX()); - } - - // [5] [4] [3] [2] [1] ___| - public void testLayout5KeyR1() { - MiniKeyboardParams params = new MiniKeyboardParams(5, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R1, KEYBOARD_WIDTH); - assertEquals("5 key R1 columns", 5, params.mNumColumns); - assertEquals("5 key R1 rows", 1, params.mNumRows); - assertEquals("5 key R1 left", 4, params.mLeftKeys); - assertEquals("5 key R1 right", 1, params.mRightKeys); - assertEquals("5 key R1 [1]", 0, params.getColumnPos(0)); - assertEquals("5 key R1 [2]", -1, params.getColumnPos(1)); - assertEquals("5 key R1 [3]", -2, params.getColumnPos(2)); - assertEquals("5 key R1 [4]", -3, params.getColumnPos(3)); - assertEquals("5 key R1 [5]", -4, params.getColumnPos(4)); - assertEquals("5 key R1 adjust", 0, params.mTopRowAdjustment); - assertEquals("5 key R1 default", WIDTH * 4, params.getDefaultKeyCoordX()); - } - - // [5] [4] [3] [1] [2] ___ ___| - public void testLayout5KeyR2() { - MiniKeyboardParams params = new MiniKeyboardParams(5, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R2, KEYBOARD_WIDTH); - assertEquals("5 key R2 columns", 5, params.mNumColumns); - assertEquals("5 key R2 rows", 1, params.mNumRows); - assertEquals("5 key R2 left", 3, params.mLeftKeys); - assertEquals("5 key R2 right", 2, params.mRightKeys); - assertEquals("5 key R2 [1]", 0, params.getColumnPos(0)); - assertEquals("5 key R2 [2]", 1, params.getColumnPos(1)); - assertEquals("5 key R2 [3]", -1, params.getColumnPos(2)); - assertEquals("5 key R2 [4]", -2, params.getColumnPos(3)); - assertEquals("5 key R2 [5]", -3, params.getColumnPos(4)); - assertEquals("5 key R2 adjust", 0, params.mTopRowAdjustment); - assertEquals("5 key R2 default", WIDTH * 3, params.getDefaultKeyCoordX()); - } - - // [6] [4] [5] - // [3] [1] [2] - public void testLayout6KeyM0() { - MiniKeyboardParams params = new MiniKeyboardParams(6, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_M0, KEYBOARD_WIDTH); - assertEquals("6 key columns", 3, params.mNumColumns); - assertEquals("6 key rows", 2, params.mNumRows); - assertEquals("6 key left", 1, params.mLeftKeys); - assertEquals("6 key right", 2, params.mRightKeys); - assertEquals("6 key [1]", 0, params.getColumnPos(0)); - assertEquals("6 key [2]", 1, params.getColumnPos(1)); - assertEquals("6 key [3]", -1, params.getColumnPos(2)); - assertEquals("6 key [4]", 0, params.getColumnPos(3)); - assertEquals("6 key [5]", 1, params.getColumnPos(4)); - assertEquals("6 key [6]", -1, params.getColumnPos(5)); - assertEquals("6 key adjust", 0, params.mTopRowAdjustment); - assertEquals("6 key default", WIDTH * 1, params.getDefaultKeyCoordX()); - } - - // |[4] [5] [6] - // |[1] [2] [3] - public void testLayout6KeyL0() { - MiniKeyboardParams params = new MiniKeyboardParams(6, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L0, KEYBOARD_WIDTH); - assertEquals("6 key L0 columns", 3, params.mNumColumns); - assertEquals("6 key L0 rows", 2, params.mNumRows); - assertEquals("6 key L0 left", 0, params.mLeftKeys); - assertEquals("6 key L0 right", 3, params.mRightKeys); - assertEquals("6 key L0 [1]", 0, params.getColumnPos(0)); - assertEquals("6 key L0 [2]", 1, params.getColumnPos(1)); - assertEquals("6 key L0 [3]", 2, params.getColumnPos(2)); - assertEquals("6 key L0 [4]", 0, params.getColumnPos(3)); - assertEquals("6 key L0 [5]", 1, params.getColumnPos(4)); - assertEquals("6 key L0 [6]", 2, params.getColumnPos(5)); - assertEquals("6 key L0 adjust", 0, params.mTopRowAdjustment); - assertEquals("6 key L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ [4] [5] [6] - // |___ [1] [2] [3] - public void testLayout6KeyL1() { - MiniKeyboardParams params = new MiniKeyboardParams(6, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L1, KEYBOARD_WIDTH); - assertEquals("6 key L1 columns", 3, params.mNumColumns); - assertEquals("6 key L1 rows", 2, params.mNumRows); - assertEquals("6 key L1 left", 0, params.mLeftKeys); - assertEquals("6 key L1 right", 3, params.mRightKeys); - assertEquals("6 key L1 [1]", 0, params.getColumnPos(0)); - assertEquals("6 key L1 [2]", 1, params.getColumnPos(1)); - assertEquals("6 key L1 [3]", 2, params.getColumnPos(2)); - assertEquals("6 key L1 [4]", 0, params.getColumnPos(3)); - assertEquals("6 key L1 [5]", 1, params.getColumnPos(4)); - assertEquals("6 key L1 [6]", 2, params.getColumnPos(5)); - assertEquals("6 key L1 adjust", 0, params.mTopRowAdjustment); - assertEquals("6 key L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ ___ [6] [4] [5] - // |___ ___ [3] [1] [2] - public void testLayout6KeyL2() { - MiniKeyboardParams params = new MiniKeyboardParams(6, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L2, KEYBOARD_WIDTH); - assertEquals("6 key L2 columns", 3, params.mNumColumns); - assertEquals("6 key L2 rows", 2, params.mNumRows); - assertEquals("6 key L2 left", 1, params.mLeftKeys); - assertEquals("6 key L2 right", 2, params.mRightKeys); - assertEquals("6 key L2 [1]", 0, params.getColumnPos(0)); - assertEquals("6 key L2 [2]", 1, params.getColumnPos(1)); - assertEquals("6 key L2 [3]", -1, params.getColumnPos(2)); - assertEquals("6 key L2 [4]", 0, params.getColumnPos(3)); - assertEquals("6 key L2 [5]", 1, params.getColumnPos(4)); - assertEquals("6 key L2 [6]", -1, params.getColumnPos(5)); - assertEquals("6 key L2 adjust", 0, params.mTopRowAdjustment); - assertEquals("6 key L2 default", WIDTH * 1, params.getDefaultKeyCoordX()); - } - - // [6] [5] [4]| - // [3] [2] [1]| - public void testLayout6KeyR0() { - MiniKeyboardParams params = new MiniKeyboardParams(6, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R0, KEYBOARD_WIDTH); - assertEquals("6 key R0 columns", 3, params.mNumColumns); - assertEquals("6 key R0 rows", 2, params.mNumRows); - assertEquals("6 key R0 left", 2, params.mLeftKeys); - assertEquals("6 key R0 right", 1, params.mRightKeys); - assertEquals("6 key R0 [1]", 0, params.getColumnPos(0)); - assertEquals("6 key R0 [2]", -1, params.getColumnPos(1)); - assertEquals("6 key R0 [3]", -2, params.getColumnPos(2)); - assertEquals("6 key R0 [4]", 0, params.getColumnPos(3)); - assertEquals("6 key R0 [5]", -1, params.getColumnPos(4)); - assertEquals("6 key R0 [6]", -2, params.getColumnPos(5)); - assertEquals("6 key R0 adjust", 0, params.mTopRowAdjustment); - assertEquals("6 key R0 default", WIDTH * 2, params.getDefaultKeyCoordX()); - } - - // [6] [5] [4] ___| - // [3] [2] [1] ___| - public void testLayout6KeyR1() { - MiniKeyboardParams params = new MiniKeyboardParams(6, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R1, KEYBOARD_WIDTH); - assertEquals("6 key R1 columns", 3, params.mNumColumns); - assertEquals("6 key R1 rows", 2, params.mNumRows); - assertEquals("6 key R1 left", 2, params.mLeftKeys); - assertEquals("6 key R1 right", 1, params.mRightKeys); - assertEquals("6 key R1 [1]", 0, params.getColumnPos(0)); - assertEquals("6 key R1 [2]", -1, params.getColumnPos(1)); - assertEquals("6 key R1 [3]", -2, params.getColumnPos(2)); - assertEquals("6 key R1 [4]", 0, params.getColumnPos(3)); - assertEquals("6 key R1 [5]", -1, params.getColumnPos(4)); - assertEquals("6 key R1 [6]", -2, params.getColumnPos(5)); - assertEquals("6 key R1 adjust", 0, params.mTopRowAdjustment); - assertEquals("6 key R1 default", WIDTH * 2, params.getDefaultKeyCoordX()); - } - - // [6] [4] [5] ___ ___| - // [3] [1] [2] ___ ___| - public void testLayout6KeyR2() { - MiniKeyboardParams params = new MiniKeyboardParams(6, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R2, KEYBOARD_WIDTH); - assertEquals("6 key R2 columns", 3, params.mNumColumns); - assertEquals("6 key R2 rows", 2, params.mNumRows); - assertEquals("6 key R2 left", 1, params.mLeftKeys); - assertEquals("6 key R2 right", 2, params.mRightKeys); - assertEquals("6 key R2 [1]", 0, params.getColumnPos(0)); - assertEquals("6 key R2 [2]", 1, params.getColumnPos(1)); - assertEquals("6 key R2 [3]", -1, params.getColumnPos(2)); - assertEquals("6 key R2 [4]", 0, params.getColumnPos(3)); - assertEquals("6 key R2 [5]", 1, params.getColumnPos(4)); - assertEquals("6 key R2 [6]", -1, params.getColumnPos(5)); - assertEquals("6 key R2 adjust", 0, params.mTopRowAdjustment); - assertEquals("6 key R2 default", WIDTH * 1, params.getDefaultKeyCoordX()); - } - - // [7] [5] [6] - // [3] [1] [2] [4] - public void testLayout7KeyM0() { - MiniKeyboardParams params = new MiniKeyboardParams(7, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_M0, KEYBOARD_WIDTH); - assertEquals("7 key columns", 4, params.mNumColumns); - assertEquals("7 key rows", 2, params.mNumRows); - assertEquals("7 key left", 1, params.mLeftKeys); - assertEquals("7 key right", 3, params.mRightKeys); - assertEquals("7 key [1]", 0, params.getColumnPos(0)); - assertEquals("7 key [2]", 1, params.getColumnPos(1)); - assertEquals("7 key [3]", -1, params.getColumnPos(2)); - assertEquals("7 key [4]", 2, params.getColumnPos(3)); - assertEquals("7 key [5]", 0, params.getColumnPos(4)); - assertEquals("7 key [6]", 1, params.getColumnPos(5)); - assertEquals("7 key [7]", -1, params.getColumnPos(6)); - assertEquals("7 key adjust", 1, params.mTopRowAdjustment); - assertEquals("7 key default", WIDTH * 1, params.getDefaultKeyCoordX()); - } - - // |[5] [6] [7] - // |[1] [2] [3] [4] - public void testLayout7KeyL0() { - MiniKeyboardParams params = new MiniKeyboardParams(7, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L0, KEYBOARD_WIDTH); - assertEquals("7 key L0 columns", 4, params.mNumColumns); - assertEquals("7 key L0 rows", 2, params.mNumRows); - assertEquals("7 key L0 left", 0, params.mLeftKeys); - assertEquals("7 key L0 right", 4, params.mRightKeys); - assertEquals("7 key L0 [1]", 0, params.getColumnPos(0)); - assertEquals("7 key L0 [2]", 1, params.getColumnPos(1)); - assertEquals("7 key L0 [3]", 2, params.getColumnPos(2)); - assertEquals("7 key L0 [4]", 3, params.getColumnPos(3)); - assertEquals("7 key L0 [5]", 0, params.getColumnPos(4)); - assertEquals("7 key L0 [6]", 1, params.getColumnPos(5)); - assertEquals("7 key L0 [7]", 2, params.getColumnPos(6)); - assertEquals("7 key L0 adjust", 0, params.mTopRowAdjustment); - assertEquals("7 key L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ [5] [6] [7] - // |___ [1] [2] [3] [4] - public void testLayout7KeyL1() { - MiniKeyboardParams params = new MiniKeyboardParams(7, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L1, KEYBOARD_WIDTH); - assertEquals("7 key L1 columns", 4, params.mNumColumns); - assertEquals("7 key L1 rows", 2, params.mNumRows); - assertEquals("7 key L1 left", 0, params.mLeftKeys); - assertEquals("7 key L1 right", 4, params.mRightKeys); - assertEquals("7 key L1 [1]", 0, params.getColumnPos(0)); - assertEquals("7 key L1 [2]", 1, params.getColumnPos(1)); - assertEquals("7 key L1 [3]", 2, params.getColumnPos(2)); - assertEquals("7 key L1 [4]", 3, params.getColumnPos(3)); - assertEquals("7 key L1 [5]", 0, params.getColumnPos(4)); - assertEquals("7 key L1 [6]", 1, params.getColumnPos(5)); - assertEquals("7 key L1 [7]", 2, params.getColumnPos(6)); - assertEquals("7 key L1 adjust", 0, params.mTopRowAdjustment); - assertEquals("7 key L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ ___ [7] [5] [6] - // |___ ___ [3] [1] [2] [4] - public void testLayout7KeyL2() { - MiniKeyboardParams params = new MiniKeyboardParams(7, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L2, KEYBOARD_WIDTH); - assertEquals("7 key L2 columns", 4, params.mNumColumns); - assertEquals("7 key L2 rows", 2, params.mNumRows); - assertEquals("7 key L2 left", 1, params.mLeftKeys); - assertEquals("7 key L2 right", 3, params.mRightKeys); - assertEquals("7 key L2 [1]", 0, params.getColumnPos(0)); - assertEquals("7 key L2 [2]", 1, params.getColumnPos(1)); - assertEquals("7 key L2 [3]", -1, params.getColumnPos(2)); - assertEquals("7 key L2 [4]", 2, params.getColumnPos(3)); - assertEquals("7 key L2 [5]", 0, params.getColumnPos(4)); - assertEquals("7 key L2 [6]", 1, params.getColumnPos(5)); - assertEquals("7 key L2 [7]", -1, params.getColumnPos(6)); - assertEquals("7 key L2 adjust", 1, params.mTopRowAdjustment); - assertEquals("7 key L2 default", WIDTH * 1, params.getDefaultKeyCoordX()); - } - - // [7] [6] [5]| - // [4] [3] [2] [1]| - public void testLayout7KeyR0() { - MiniKeyboardParams params = new MiniKeyboardParams(7, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R0, KEYBOARD_WIDTH); - assertEquals("7 key R0 columns", 4, params.mNumColumns); - assertEquals("7 key R0 rows", 2, params.mNumRows); - assertEquals("7 key R0 left", 3, params.mLeftKeys); - assertEquals("7 key R0 right", 1, params.mRightKeys); - assertEquals("7 key R0 [1]", 0, params.getColumnPos(0)); - assertEquals("7 key R0 [2]", -1, params.getColumnPos(1)); - assertEquals("7 key R0 [3]", -2, params.getColumnPos(2)); - assertEquals("7 key R0 [4]", -3, params.getColumnPos(3)); - assertEquals("7 key R0 [5]", 0, params.getColumnPos(4)); - assertEquals("7 key R0 [6]", -1, params.getColumnPos(5)); - assertEquals("7 key R0 [7]", -2, params.getColumnPos(6)); - assertEquals("7 key R0 adjust", 0, params.mTopRowAdjustment); - assertEquals("7 key R0 default", WIDTH * 3, params.getDefaultKeyCoordX()); - } - - // [7] [6] [5] ___| - // [4] [3] [2] [1] ___| - public void testLayout7KeyR1() { - MiniKeyboardParams params = new MiniKeyboardParams(7, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R1, KEYBOARD_WIDTH); - assertEquals("7 key R1 columns", 4, params.mNumColumns); - assertEquals("7 key R1 rows", 2, params.mNumRows); - assertEquals("7 key R1 left", 3, params.mLeftKeys); - assertEquals("7 key R1 right", 1, params.mRightKeys); - assertEquals("7 key R1 [1]", 0, params.getColumnPos(0)); - assertEquals("7 key R1 [2]", -1, params.getColumnPos(1)); - assertEquals("7 key R1 [3]", -2, params.getColumnPos(2)); - assertEquals("7 key R1 [4]", -3, params.getColumnPos(3)); - assertEquals("7 key R1 [5]", 0, params.getColumnPos(4)); - assertEquals("7 key R1 [6]", -1, params.getColumnPos(5)); - assertEquals("7 key R1 [7]", -2, params.getColumnPos(6)); - assertEquals("7 key R1 adjust", 0, params.mTopRowAdjustment); - assertEquals("7 key R1 default", WIDTH * 3, params.getDefaultKeyCoordX()); - } - - // [7] [5] [6] ___ ___| - // [4] [3] [1] [2] ___ ___| - public void testLayout7KeyR2() { - MiniKeyboardParams params = new MiniKeyboardParams(7, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R2, KEYBOARD_WIDTH); - assertEquals("7 key R2 columns", 4, params.mNumColumns); - assertEquals("7 key R2 rows", 2, params.mNumRows); - assertEquals("7 key R2 left", 2, params.mLeftKeys); - assertEquals("7 key R2 right", 2, params.mRightKeys); - assertEquals("7 key R2 [1]", 0, params.getColumnPos(0)); - assertEquals("7 key R2 [2]", 1, params.getColumnPos(1)); - assertEquals("7 key R2 [3]", -1, params.getColumnPos(2)); - assertEquals("7 key R2 [4]", -2, params.getColumnPos(3)); - assertEquals("7 key R2 [5]", 0, params.getColumnPos(4)); - assertEquals("7 key R2 [6]", 1, params.getColumnPos(5)); - assertEquals("7 key R2 [7]", -1, params.getColumnPos(6)); - assertEquals("7 key R2 adjust", -1, params.mTopRowAdjustment); - assertEquals("7 key R2 default", WIDTH * 2, params.getDefaultKeyCoordX()); - } - - // [7] [6] [5] [3] [1] [2] [4] ___| - public void testLayout7KeyR3Max7() { - MiniKeyboardParams params = new MiniKeyboardParams(7, 7, WIDTH, - HEIGHT, XPOS_R3, KEYBOARD_WIDTH); - assertEquals("7 key R2 columns", 7, params.mNumColumns); - assertEquals("7 key R2 rows", 1, params.mNumRows); - assertEquals("7 key R2 left", 4, params.mLeftKeys); - assertEquals("7 key R2 right", 3, params.mRightKeys); - assertEquals("7 key R2 [1]", 0, params.getColumnPos(0)); - assertEquals("7 key R2 [2]", 1, params.getColumnPos(1)); - assertEquals("7 key R2 [3]", -1, params.getColumnPos(2)); - assertEquals("7 key R2 [4]", 2, params.getColumnPos(3)); - assertEquals("7 key R2 [5]", -2, params.getColumnPos(4)); - assertEquals("7 key R2 [6]", -3, params.getColumnPos(5)); - assertEquals("7 key R2 [7]", -4, params.getColumnPos(6)); - assertEquals("7 key R2 adjust", 0, params.mTopRowAdjustment); - assertEquals("7 key R2 default", WIDTH * 4, params.getDefaultKeyCoordX()); - } - - // [7] [5] [6] [8] - // [3] [1] [2] [4] - public void testLayout8KeyM0() { - MiniKeyboardParams params = new MiniKeyboardParams(8, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_M0, KEYBOARD_WIDTH); - assertEquals("8 key M0 columns", 4, params.mNumColumns); - assertEquals("8 key M0 rows", 2, params.mNumRows); - assertEquals("8 key M0 left", 1, params.mLeftKeys); - assertEquals("8 key M0 right", 3, params.mRightKeys); - assertEquals("8 key M0 [1]", 0, params.getColumnPos(0)); - assertEquals("8 key M0 [2]", 1, params.getColumnPos(1)); - assertEquals("8 key M0 [3]", -1, params.getColumnPos(2)); - assertEquals("8 key M0 [4]", 2, params.getColumnPos(3)); - assertEquals("8 key M0 [5]", 0, params.getColumnPos(4)); - assertEquals("8 key M0 [6]", 1, params.getColumnPos(5)); - assertEquals("8 key M0 [7]", -1, params.getColumnPos(6)); - assertEquals("8 key M0 [8]", 2, params.getColumnPos(7)); - assertEquals("8 key M0 adjust", 0, params.mTopRowAdjustment); - assertEquals("8 key M0 default", WIDTH * 1, params.getDefaultKeyCoordX()); - } - - // |[5] [6] [7] [8] - // |[1] [2] [3] [4] - public void testLayout8KeyL0() { - MiniKeyboardParams params = new MiniKeyboardParams(8, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L0, KEYBOARD_WIDTH); - assertEquals("8 key L0 columns", 4, params.mNumColumns); - assertEquals("8 key L0 rows", 2, params.mNumRows); - assertEquals("8 key L0 left", 0, params.mLeftKeys); - assertEquals("8 key L0 right", 4, params.mRightKeys); - assertEquals("8 key L0 [1]", 0, params.getColumnPos(0)); - assertEquals("8 key L0 [2]", 1, params.getColumnPos(1)); - assertEquals("8 key L0 [3]", 2, params.getColumnPos(2)); - assertEquals("8 key L0 [4]", 3, params.getColumnPos(3)); - assertEquals("8 key L0 [5]", 0, params.getColumnPos(4)); - assertEquals("8 key L0 [6]", 1, params.getColumnPos(5)); - assertEquals("8 key L0 [7]", 2, params.getColumnPos(6)); - assertEquals("8 key L0 [8]", 3, params.getColumnPos(7)); - assertEquals("8 key L0 adjust", 0, params.mTopRowAdjustment); - assertEquals("8 key L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ [5] [6] [7] [8] - // |___ [1] [2] [3] [4] - public void testLayout8KeyL1() { - MiniKeyboardParams params = new MiniKeyboardParams(8, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L1, KEYBOARD_WIDTH); - assertEquals("8 key L1 columns", 4, params.mNumColumns); - assertEquals("8 key L1 rows", 2, params.mNumRows); - assertEquals("8 key L1 left", 0, params.mLeftKeys); - assertEquals("8 key L1 right", 4, params.mRightKeys); - assertEquals("8 key L1 [1]", 0, params.getColumnPos(0)); - assertEquals("8 key L1 [2]", 1, params.getColumnPos(1)); - assertEquals("8 key L1 [3]", 2, params.getColumnPos(2)); - assertEquals("8 key L1 [4]", 3, params.getColumnPos(3)); - assertEquals("8 key L1 [5]", 0, params.getColumnPos(4)); - assertEquals("8 key L1 [6]", 1, params.getColumnPos(5)); - assertEquals("8 key L1 [7]", 2, params.getColumnPos(6)); - assertEquals("8 key L1 [8]", 3, params.getColumnPos(7)); - assertEquals("8 key L1 adjust", 0, params.mTopRowAdjustment); - assertEquals("8 key L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ ___ [7] [5] [6] [8] - // |___ ___ [3] [1] [2] [4] - public void testLayout8KeyL2() { - MiniKeyboardParams params = new MiniKeyboardParams(8, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L2, KEYBOARD_WIDTH); - assertEquals("8 key L2 columns", 4, params.mNumColumns); - assertEquals("8 key L2 rows", 2, params.mNumRows); - assertEquals("8 key L2 left", 1, params.mLeftKeys); - assertEquals("8 key L2 right", 3, params.mRightKeys); - assertEquals("8 key L2 [1]", 0, params.getColumnPos(0)); - assertEquals("8 key L2 [2]", 1, params.getColumnPos(1)); - assertEquals("8 key L2 [3]", -1, params.getColumnPos(2)); - assertEquals("8 key L2 [4]", 2, params.getColumnPos(3)); - assertEquals("8 key L2 [5]", 0, params.getColumnPos(4)); - assertEquals("8 key L2 [6]", 1, params.getColumnPos(5)); - assertEquals("8 key L2 [7]", -1, params.getColumnPos(6)); - assertEquals("8 key L2 [8]", 2, params.getColumnPos(7)); - assertEquals("8 key L2 adjust", 0, params.mTopRowAdjustment); - assertEquals("8 key L2 default", WIDTH * 1, params.getDefaultKeyCoordX()); - } - - // [8] [7] [6] [5]| - // [4] [3] [2] [1]| - public void testLayout8KeyR0() { - MiniKeyboardParams params = new MiniKeyboardParams(8, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R0, KEYBOARD_WIDTH); - assertEquals("8 key R0 columns", 4, params.mNumColumns); - assertEquals("8 key R0 rows", 2, params.mNumRows); - assertEquals("8 key R0 left", 3, params.mLeftKeys); - assertEquals("8 key R0 right", 1, params.mRightKeys); - assertEquals("8 key R0 [1]", 0, params.getColumnPos(0)); - assertEquals("8 key R0 [2]", -1, params.getColumnPos(1)); - assertEquals("8 key R0 [3]", -2, params.getColumnPos(2)); - assertEquals("8 key R0 [4]", -3, params.getColumnPos(3)); - assertEquals("8 key R0 [5]", 0, params.getColumnPos(4)); - assertEquals("8 key R0 [6]", -1, params.getColumnPos(5)); - assertEquals("8 key R0 [7]", -2, params.getColumnPos(6)); - assertEquals("8 key R0 [8]", -3, params.getColumnPos(7)); - assertEquals("8 key R0 adjust", 0, params.mTopRowAdjustment); - assertEquals("8 key R0 default", WIDTH * 3, params.getDefaultKeyCoordX()); - } - - // [8] [7] [6] [5] ___| - // [4] [3] [2] [1] ___| - public void testLayout8KeyR1() { - MiniKeyboardParams params = new MiniKeyboardParams(8, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R1, KEYBOARD_WIDTH); - assertEquals("8 key R1 columns", 4, params.mNumColumns); - assertEquals("8 key R1 rows", 2, params.mNumRows); - assertEquals("8 key R1 left", 3, params.mLeftKeys); - assertEquals("8 key R1 right", 1, params.mRightKeys); - assertEquals("8 key R1 [1]", 0, params.getColumnPos(0)); - assertEquals("8 key R1 [2]", -1, params.getColumnPos(1)); - assertEquals("8 key R1 [3]", -2, params.getColumnPos(2)); - assertEquals("8 key R1 [4]", -3, params.getColumnPos(3)); - assertEquals("8 key R1 [5]", 0, params.getColumnPos(4)); - assertEquals("8 key R1 [6]", -1, params.getColumnPos(5)); - assertEquals("8 key R1 [7]", -2, params.getColumnPos(6)); - assertEquals("8 key R1 [8]", -3, params.getColumnPos(7)); - assertEquals("8 key R1 adjust", 0, params.mTopRowAdjustment); - assertEquals("8 key R1 default", WIDTH * 3, params.getDefaultKeyCoordX()); - } - - // [8] [7] [5] [6] ___ ___| - // [4] [3] [1] [2] ___ ___| - public void testLayout8KeyR2() { - MiniKeyboardParams params = new MiniKeyboardParams(8, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R2, KEYBOARD_WIDTH); - assertEquals("8 key R2 columns", 4, params.mNumColumns); - assertEquals("8 key R2 rows", 2, params.mNumRows); - assertEquals("8 key R2 left", 2, params.mLeftKeys); - assertEquals("8 key R2 right", 2, params.mRightKeys); - assertEquals("8 key R2 [1]", 0, params.getColumnPos(0)); - assertEquals("8 key R2 [2]", 1, params.getColumnPos(1)); - assertEquals("8 key R2 [3]", -1, params.getColumnPos(2)); - assertEquals("8 key R2 [4]", -2, params.getColumnPos(3)); - assertEquals("8 key R2 [5]", 0, params.getColumnPos(4)); - assertEquals("8 key R2 [6]", 1, params.getColumnPos(5)); - assertEquals("8 key R2 [7]", -1, params.getColumnPos(6)); - assertEquals("8 key R2 [8]", -2, params.getColumnPos(7)); - assertEquals("8 key R2 adjust", 0, params.mTopRowAdjustment); - assertEquals("8 key R2 default", WIDTH * 2, params.getDefaultKeyCoordX()); - } - - // [8] [6] [7] [9] - // [5] [3] [1] [2] [4] - public void testLayout9KeyM0() { - MiniKeyboardParams params = new MiniKeyboardParams(9, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_M0, KEYBOARD_WIDTH); - assertEquals("9 key M0 columns", 5, params.mNumColumns); - assertEquals("9 key M0 rows", 2, params.mNumRows); - assertEquals("9 key M0 left", 2, params.mLeftKeys); - assertEquals("9 key M0 right", 3, params.mRightKeys); - assertEquals("9 key M0 [1]", 0, params.getColumnPos(0)); - assertEquals("9 key M0 [2]", 1, params.getColumnPos(1)); - assertEquals("9 key M0 [3]", -1, params.getColumnPos(2)); - assertEquals("9 key M0 [4]", 2, params.getColumnPos(3)); - assertEquals("9 key M0 [5]", -2, params.getColumnPos(4)); - assertEquals("9 key M0 [6]", 0, params.getColumnPos(5)); - assertEquals("9 key M0 [7]", 1, params.getColumnPos(6)); - assertEquals("9 key M0 [8]", -1, params.getColumnPos(7)); - assertEquals("9 key M0 [9]", 2, params.getColumnPos(8)); - assertEquals("9 key M0 adjust", -1, params.mTopRowAdjustment); - assertEquals("9 key M0 default", WIDTH * 2, params.getDefaultKeyCoordX()); - } - - // |[6] [7] [8] [9] - // |[1] [2] [3] [4] [5] - public void testLayout9KeyL0() { - MiniKeyboardParams params = new MiniKeyboardParams(9, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L0, KEYBOARD_WIDTH); - assertEquals("9 key L0 columns", 5, params.mNumColumns); - assertEquals("9 key L0 rows", 2, params.mNumRows); - assertEquals("9 key L0 left", 0, params.mLeftKeys); - assertEquals("9 key L0 right", 5, params.mRightKeys); - assertEquals("9 key L0 [1]", 0, params.getColumnPos(0)); - assertEquals("9 key L0 [2]", 1, params.getColumnPos(1)); - assertEquals("9 key L0 [3]", 2, params.getColumnPos(2)); - assertEquals("9 key L0 [4]", 3, params.getColumnPos(3)); - assertEquals("9 key L0 [5]", 4, params.getColumnPos(4)); - assertEquals("9 key L0 [6]", 0, params.getColumnPos(5)); - assertEquals("9 key L0 [7]", 1, params.getColumnPos(6)); - assertEquals("9 key L0 [8]", 2, params.getColumnPos(7)); - assertEquals("9 key L0 [9]", 3, params.getColumnPos(8)); - assertEquals("9 key L0 adjust", 0, params.mTopRowAdjustment); - assertEquals("9 key L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ [6] [7] [8] [9] - // |___ [1] [2] [3] [4] [5] - public void testLayout9KeyL1() { - MiniKeyboardParams params = new MiniKeyboardParams(9, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L1, KEYBOARD_WIDTH); - assertEquals("9 key L1 columns", 5, params.mNumColumns); - assertEquals("9 key L1 rows", 2, params.mNumRows); - assertEquals("9 key L1 left", 0, params.mLeftKeys); - assertEquals("9 key L1 right", 5, params.mRightKeys); - assertEquals("9 key L1 [1]", 0, params.getColumnPos(0)); - assertEquals("9 key L1 [2]", 1, params.getColumnPos(1)); - assertEquals("9 key L1 [3]", 2, params.getColumnPos(2)); - assertEquals("9 key L1 [4]", 3, params.getColumnPos(3)); - assertEquals("9 key L1 [5]", 4, params.getColumnPos(4)); - assertEquals("9 key L1 [6]", 0, params.getColumnPos(5)); - assertEquals("9 key L1 [7]", 1, params.getColumnPos(6)); - assertEquals("9 key L1 [8]", 2, params.getColumnPos(7)); - assertEquals("9 key L1 [9]", 3, params.getColumnPos(8)); - assertEquals("9 key L1 adjust", 0, params.mTopRowAdjustment); - assertEquals("9 key L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ ___ [8] [6] [7] [9] - // |___ ___ [3] [1] [2] [4] [5] - public void testLayout9KeyL2() { - MiniKeyboardParams params = new MiniKeyboardParams(9, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L2, KEYBOARD_WIDTH); - assertEquals("9 key L2 columns", 5, params.mNumColumns); - assertEquals("9 key L2 rows", 2, params.mNumRows); - assertEquals("9 key L2 left", 1, params.mLeftKeys); - assertEquals("9 key L2 right", 4, params.mRightKeys); - assertEquals("9 key L2 [1]", 0, params.getColumnPos(0)); - assertEquals("9 key L2 [2]", 1, params.getColumnPos(1)); - assertEquals("9 key L2 [3]", -1, params.getColumnPos(2)); - assertEquals("9 key L2 [4]", 2, params.getColumnPos(3)); - assertEquals("9 key L2 [5]", 3, params.getColumnPos(4)); - assertEquals("9 key L2 [6]", 0, params.getColumnPos(5)); - assertEquals("9 key L2 [7]", 1, params.getColumnPos(6)); - assertEquals("9 key L2 [8]", -1, params.getColumnPos(7)); - assertEquals("9 key L2 [9]", 2, params.getColumnPos(8)); - assertEquals("9 key L2 adjust", 1, params.mTopRowAdjustment); - assertEquals("9 key L2 default", WIDTH * 1, params.getDefaultKeyCoordX()); - } - - // [9] [8] [7] [6]| - // [5] [4] [3] [2] [1]| - public void testLayout9KeyR0() { - MiniKeyboardParams params = new MiniKeyboardParams(9, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R0, KEYBOARD_WIDTH); - assertEquals("9 key R0 columns", 5, params.mNumColumns); - assertEquals("9 key R0 rows", 2, params.mNumRows); - assertEquals("9 key R0 left", 4, params.mLeftKeys); - assertEquals("9 key R0 right", 1, params.mRightKeys); - assertEquals("9 key R0 [1]", 0, params.getColumnPos(0)); - assertEquals("9 key R0 [2]", -1, params.getColumnPos(1)); - assertEquals("9 key R0 [3]", -2, params.getColumnPos(2)); - assertEquals("9 key R0 [4]", -3, params.getColumnPos(3)); - assertEquals("9 key R0 [5]", -4, params.getColumnPos(4)); - assertEquals("9 key R0 [6]", 0, params.getColumnPos(5)); - assertEquals("9 key R0 [7]", -1, params.getColumnPos(6)); - assertEquals("9 key R0 [8]", -2, params.getColumnPos(7)); - assertEquals("9 key R0 [9]", -3, params.getColumnPos(8)); - assertEquals("9 key R0 adjust", 0, params.mTopRowAdjustment); - assertEquals("9 key R0 default", WIDTH * 4, params.getDefaultKeyCoordX()); - } - - // [9] [8] [7] [6] ___| - // [5] [4] [3] [2] [1] ___| - public void testLayout9KeyR1() { - MiniKeyboardParams params = new MiniKeyboardParams(9, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R1, KEYBOARD_WIDTH); - assertEquals("9 key R1 columns", 5, params.mNumColumns); - assertEquals("9 key R1 rows", 2, params.mNumRows); - assertEquals("9 key R1 left", 4, params.mLeftKeys); - assertEquals("9 key R1 right", 1, params.mRightKeys); - assertEquals("9 key R1 [1]", 0, params.getColumnPos(0)); - assertEquals("9 key R1 [2]", -1, params.getColumnPos(1)); - assertEquals("9 key R1 [3]", -2, params.getColumnPos(2)); - assertEquals("9 key R1 [4]", -3, params.getColumnPos(3)); - assertEquals("9 key R1 [5]", -4, params.getColumnPos(4)); - assertEquals("9 key R1 [6]", 0, params.getColumnPos(5)); - assertEquals("9 key R1 [7]", -1, params.getColumnPos(6)); - assertEquals("9 key R1 [8]", -2, params.getColumnPos(7)); - assertEquals("9 key R1 [9]", -3, params.getColumnPos(8)); - assertEquals("9 key R1 adjust", 0, params.mTopRowAdjustment); - assertEquals("9 key R1 default", WIDTH * 4, params.getDefaultKeyCoordX()); - } - - // [9] [8] [6] [7] ___ ___| - // [5] [4] [3] [1] [2] ___ ___| - public void testLayout9KeyR2() { - MiniKeyboardParams params = new MiniKeyboardParams(9, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R2, KEYBOARD_WIDTH); - assertEquals("9 key R2 columns", 5, params.mNumColumns); - assertEquals("9 key R2 rows", 2, params.mNumRows); - assertEquals("9 key R2 left", 3, params.mLeftKeys); - assertEquals("9 key R2 right", 2, params.mRightKeys); - assertEquals("9 key R2 [1]", 0, params.getColumnPos(0)); - assertEquals("9 key R2 [2]", 1, params.getColumnPos(1)); - assertEquals("9 key R2 [3]", -1, params.getColumnPos(2)); - assertEquals("9 key R2 [4]", -2, params.getColumnPos(3)); - assertEquals("9 key R2 [5]", -3, params.getColumnPos(4)); - assertEquals("9 key R2 [6]", 0, params.getColumnPos(5)); - assertEquals("9 key R2 [7]", 1, params.getColumnPos(6)); - assertEquals("9 key R2 [8]", -1, params.getColumnPos(7)); - assertEquals("9 key R2 [9]", -2, params.getColumnPos(8)); - assertEquals("9 key R2 adjust", -1, params.mTopRowAdjustment); - assertEquals("9 key R2 default", WIDTH * 3, params.getDefaultKeyCoordX()); - } - - // [A] [8] [6] [7] [9] - // [5] [3] [1] [2] [4] - public void testLayout10KeyM0() { - MiniKeyboardParams params = new MiniKeyboardParams(10, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_M0, KEYBOARD_WIDTH); - assertEquals("10 key M0 columns", 5, params.mNumColumns); - assertEquals("10 key M0 rows", 2, params.mNumRows); - assertEquals("10 key M0 left", 2, params.mLeftKeys); - assertEquals("10 key M0 right", 3, params.mRightKeys); - assertEquals("10 key M0 [1]", 0, params.getColumnPos(0)); - assertEquals("10 key M0 [2]", 1, params.getColumnPos(1)); - assertEquals("10 key M0 [3]", -1, params.getColumnPos(2)); - assertEquals("10 key M0 [4]", 2, params.getColumnPos(3)); - assertEquals("10 key M0 [5]", -2, params.getColumnPos(4)); - assertEquals("10 key M0 [6]", 0, params.getColumnPos(5)); - assertEquals("10 key M0 [7]", 1, params.getColumnPos(6)); - assertEquals("10 key M0 [8]", -1, params.getColumnPos(7)); - assertEquals("10 key M0 [9]", 2, params.getColumnPos(8)); - assertEquals("10 key M0 [A]", -2, params.getColumnPos(9)); - assertEquals("10 key M0 adjust", 0, params.mTopRowAdjustment); - assertEquals("10 key M0 default", WIDTH * 2, params.getDefaultKeyCoordX()); - } - - // |[6] [7] [8] [9] [A] - // |[1] [2] [3] [4] [5] - public void testLayout10KeyL0() { - MiniKeyboardParams params = new MiniKeyboardParams(10, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L0, KEYBOARD_WIDTH); - assertEquals("10 key L0 columns", 5, params.mNumColumns); - assertEquals("10 key L0 rows", 2, params.mNumRows); - assertEquals("10 key L0 left", 0, params.mLeftKeys); - assertEquals("10 key L0 right", 5, params.mRightKeys); - assertEquals("10 key L0 [1]", 0, params.getColumnPos(0)); - assertEquals("10 key L0 [2]", 1, params.getColumnPos(1)); - assertEquals("10 key L0 [3]", 2, params.getColumnPos(2)); - assertEquals("10 key L0 [4]", 3, params.getColumnPos(3)); - assertEquals("10 key L0 [5]", 4, params.getColumnPos(4)); - assertEquals("10 key L0 [6]", 0, params.getColumnPos(5)); - assertEquals("10 key L0 [7]", 1, params.getColumnPos(6)); - assertEquals("10 key L0 [8]", 2, params.getColumnPos(7)); - assertEquals("10 key L0 [9]", 3, params.getColumnPos(8)); - assertEquals("10 key L0 [A]", 4, params.getColumnPos(9)); - assertEquals("10 key L0 adjust", 0, params.mTopRowAdjustment); - assertEquals("10 key L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ [6] [7] [8] [9] [A] - // |___ [1] [2] [3] [4] [5] - public void testLayout10KeyL1() { - MiniKeyboardParams params = new MiniKeyboardParams(10, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L1, KEYBOARD_WIDTH); - assertEquals("10 key L1 columns", 5, params.mNumColumns); - assertEquals("10 key L1 rows", 2, params.mNumRows); - assertEquals("10 key L1 left", 0, params.mLeftKeys); - assertEquals("10 key L1 right", 5, params.mRightKeys); - assertEquals("10 key L1 [1]", 0, params.getColumnPos(0)); - assertEquals("10 key L1 [2]", 1, params.getColumnPos(1)); - assertEquals("10 key L1 [3]", 2, params.getColumnPos(2)); - assertEquals("10 key L1 [4]", 3, params.getColumnPos(3)); - assertEquals("10 key L1 [5]", 4, params.getColumnPos(4)); - assertEquals("10 key L1 [6]", 0, params.getColumnPos(5)); - assertEquals("10 key L1 [7]", 1, params.getColumnPos(6)); - assertEquals("10 key L1 [8]", 2, params.getColumnPos(7)); - assertEquals("10 key L1 [9]", 3, params.getColumnPos(8)); - assertEquals("10 key L1 [A]", 4, params.getColumnPos(9)); - assertEquals("10 key L1 adjust", 0, params.mTopRowAdjustment); - assertEquals("10 key L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); - } - - // |___ ___ [8] [6] [7] [9] [A] - // |___ ___ [3] [1] [2] [4] [5] - public void testLayout10KeyL2() { - MiniKeyboardParams params = new MiniKeyboardParams(10, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_L2, KEYBOARD_WIDTH); - assertEquals("10 key L2 columns", 5, params.mNumColumns); - assertEquals("10 key L2 rows", 2, params.mNumRows); - assertEquals("10 key L2 left", 1, params.mLeftKeys); - assertEquals("10 key L2 right", 4, params.mRightKeys); - assertEquals("10 key L2 [1]", 0, params.getColumnPos(0)); - assertEquals("10 key L2 [2]", 1, params.getColumnPos(1)); - assertEquals("10 key L2 [3]", -1, params.getColumnPos(2)); - assertEquals("10 key L2 [4]", 2, params.getColumnPos(3)); - assertEquals("10 key L2 [5]", 3, params.getColumnPos(4)); - assertEquals("10 key L2 [6]", 0, params.getColumnPos(5)); - assertEquals("10 key L2 [7]", 1, params.getColumnPos(6)); - assertEquals("10 key L2 [8]", -1, params.getColumnPos(7)); - assertEquals("10 key L2 [9]", 2, params.getColumnPos(8)); - assertEquals("10 key L2 [A]", 3, params.getColumnPos(9)); - assertEquals("10 key L2 adjust", 0, params.mTopRowAdjustment); - assertEquals("10 key L2 default", WIDTH * 1, params.getDefaultKeyCoordX()); - } - - // [A] [9] [8] [7] [6]| - // [5] [4] [3] [2] [1]| - public void testLayout10KeyR0() { - MiniKeyboardParams params = new MiniKeyboardParams(10, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R0, KEYBOARD_WIDTH); - assertEquals("10 key R0 columns", 5, params.mNumColumns); - assertEquals("10 key R0 rows", 2, params.mNumRows); - assertEquals("10 key R0 left", 4, params.mLeftKeys); - assertEquals("10 key R0 right", 1, params.mRightKeys); - assertEquals("10 key R0 [1]", 0, params.getColumnPos(0)); - assertEquals("10 key R0 [2]", -1, params.getColumnPos(1)); - assertEquals("10 key R0 [3]", -2, params.getColumnPos(2)); - assertEquals("10 key R0 [4]", -3, params.getColumnPos(3)); - assertEquals("10 key R0 [5]", -4, params.getColumnPos(4)); - assertEquals("10 key R0 [6]", 0, params.getColumnPos(5)); - assertEquals("10 key R0 [7]", -1, params.getColumnPos(6)); - assertEquals("10 key R0 [8]", -2, params.getColumnPos(7)); - assertEquals("10 key R0 [9]", -3, params.getColumnPos(8)); - assertEquals("10 key R0 [A]", -4, params.getColumnPos(9)); - assertEquals("10 key R0 adjust", 0, params.mTopRowAdjustment); - assertEquals("10 key R0 default", WIDTH * 4, params.getDefaultKeyCoordX()); - } - - // [A] [9] [8] [7] [6] ___| - // [5] [4] [3] [2] [1] ___| - public void testLayout10KeyR1() { - MiniKeyboardParams params = new MiniKeyboardParams(10, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R1, KEYBOARD_WIDTH); - assertEquals("10 key R1 columns", 5, params.mNumColumns); - assertEquals("10 key R1 rows", 2, params.mNumRows); - assertEquals("10 key R1 left", 4, params.mLeftKeys); - assertEquals("10 key R1 right", 1, params.mRightKeys); - assertEquals("10 key R1 [1]", 0, params.getColumnPos(0)); - assertEquals("10 key R1 [2]", -1, params.getColumnPos(1)); - assertEquals("10 key R1 [3]", -2, params.getColumnPos(2)); - assertEquals("10 key R1 [4]", -3, params.getColumnPos(3)); - assertEquals("10 key R1 [5]", -4, params.getColumnPos(4)); - assertEquals("10 key R1 [6]", 0, params.getColumnPos(5)); - assertEquals("10 key R1 [7]", -1, params.getColumnPos(6)); - assertEquals("10 key R1 [8]", -2, params.getColumnPos(7)); - assertEquals("10 key R1 [9]", -3, params.getColumnPos(8)); - assertEquals("10 key R1 [A]", -4, params.getColumnPos(9)); - assertEquals("10 key R1 adjust", 0, params.mTopRowAdjustment); - assertEquals("10 key R1 default", WIDTH * 4, params.getDefaultKeyCoordX()); - } - - // [A] [9] [8] [6] [7] ___ ___| - // [5] [4] [3] [1] [2] ___ ___| - public void testLayout10KeyR2() { - MiniKeyboardParams params = new MiniKeyboardParams(10, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_R2, KEYBOARD_WIDTH); - assertEquals("10 key R2 columns", 5, params.mNumColumns); - assertEquals("10 key R2 rows", 2, params.mNumRows); - assertEquals("10 key R2 left", 3, params.mLeftKeys); - assertEquals("10 key R2 right", 2, params.mRightKeys); - assertEquals("10 key R2 [1]", 0, params.getColumnPos(0)); - assertEquals("10 key R2 [2]", 1, params.getColumnPos(1)); - assertEquals("10 key R2 [3]", -1, params.getColumnPos(2)); - assertEquals("10 key R2 [4]", -2, params.getColumnPos(3)); - assertEquals("10 key R2 [5]", -3, params.getColumnPos(4)); - assertEquals("10 key R2 [6]", 0, params.getColumnPos(5)); - assertEquals("10 key R2 [7]", 1, params.getColumnPos(6)); - assertEquals("10 key R2 [8]", -1, params.getColumnPos(7)); - assertEquals("10 key R2 [9]", -2, params.getColumnPos(8)); - assertEquals("10 key R2 [A]", -3, params.getColumnPos(9)); - assertEquals("10 key R2 adjust", 0, params.mTopRowAdjustment); - assertEquals("10 key R2 default", WIDTH * 3, params.getDefaultKeyCoordX()); - } - - // [B] [9] [A] - // [7] [5] [6] [8] - // [3] [1] [2] [4] - public void testLayout11KeyM0() { - MiniKeyboardParams params = new MiniKeyboardParams(11, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_M0, KEYBOARD_WIDTH); - assertEquals("11 key M0 columns", 4, params.mNumColumns); - assertEquals("11 key M0 rows", 3, params.mNumRows); - assertEquals("11 key M0 left", 1, params.mLeftKeys); - assertEquals("11 key M0 right", 3, params.mRightKeys); - assertEquals("11 key M0 [1]", 0, params.getColumnPos(0)); - assertEquals("11 key M0 [2]", 1, params.getColumnPos(1)); - assertEquals("11 key M0 [3]", -1, params.getColumnPos(2)); - assertEquals("11 key M0 [4]", 2, params.getColumnPos(3)); - assertEquals("11 key M0 [5]", 0, params.getColumnPos(4)); - assertEquals("11 key M0 [6]", 1, params.getColumnPos(5)); - assertEquals("11 key M0 [7]", -1, params.getColumnPos(6)); - assertEquals("11 key M0 [8]", 2, params.getColumnPos(7)); - assertEquals("11 key M0 [9]", 0, params.getColumnPos(8)); - assertEquals("11 key M0 [A]", 1, params.getColumnPos(9)); - assertEquals("11 key M0 [B]", -1, params.getColumnPos(10)); - assertEquals("11 key M0 adjust", 1, params.mTopRowAdjustment); - assertEquals("11 key M0 default", WIDTH * 1, params.getDefaultKeyCoordX()); - } - - // [B] [9] [A] [C] - // [7] [5] [6] [8] - // [3] [1] [2] [4] - public void testLayout12KeyM0() { - MiniKeyboardParams params = new MiniKeyboardParams(12, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_M0, KEYBOARD_WIDTH); - assertEquals("12 key M0 columns", 4, params.mNumColumns); - assertEquals("12 key M0 rows", 3, params.mNumRows); - assertEquals("12 key M0 left", 1, params.mLeftKeys); - assertEquals("12 key M0 right", 3, params.mRightKeys); - assertEquals("12 key M0 [1]", 0, params.getColumnPos(0)); - assertEquals("12 key M0 [2]", 1, params.getColumnPos(1)); - assertEquals("12 key M0 [3]", -1, params.getColumnPos(2)); - assertEquals("12 key M0 [4]", 2, params.getColumnPos(3)); - assertEquals("12 key M0 [5]", 0, params.getColumnPos(4)); - assertEquals("12 key M0 [6]", 1, params.getColumnPos(5)); - assertEquals("12 key M0 [7]", -1, params.getColumnPos(6)); - assertEquals("12 key M0 [8]", 2, params.getColumnPos(7)); - assertEquals("12 key M0 [9]", 0, params.getColumnPos(8)); - assertEquals("12 key M0 [A]", 1, params.getColumnPos(9)); - assertEquals("12 key M0 [B]", -1, params.getColumnPos(10)); - assertEquals("12 key M0 [C]", 2, params.getColumnPos(11)); - assertEquals("12 key M0 adjust", 0, params.mTopRowAdjustment); - assertEquals("12 key M0 default", WIDTH * 1, params.getDefaultKeyCoordX()); - } - - - // [D] [B] [C] - // [A] [8] [6] [7] [9] - // [5] [3] [1] [2] [4] - public void testLayout13KeyM0() { - MiniKeyboardParams params = new MiniKeyboardParams(13, MAX_COLUMNS, WIDTH, - HEIGHT, XPOS_M0, KEYBOARD_WIDTH); - assertEquals("13 key M0 columns", 5, params.mNumColumns); - assertEquals("13 key M0 rows", 3, params.mNumRows); - assertEquals("13 key M0 left", 2, params.mLeftKeys); - assertEquals("13 key M0 right", 3, params.mRightKeys); - assertEquals("13 key M0 [1]", 0, params.getColumnPos(0)); - assertEquals("13 key M0 [2]", 1, params.getColumnPos(1)); - assertEquals("13 key M0 [3]", -1, params.getColumnPos(2)); - assertEquals("13 key M0 [4]", 2, params.getColumnPos(3)); - assertEquals("13 key M0 [5]", -2, params.getColumnPos(4)); - assertEquals("13 key M0 [6]", 0, params.getColumnPos(5)); - assertEquals("13 key M0 [7]", 1, params.getColumnPos(6)); - assertEquals("13 key M0 [8]", -1, params.getColumnPos(7)); - assertEquals("13 key M0 [9]", 2, params.getColumnPos(8)); - assertEquals("13 key M0 [A]", -2, params.getColumnPos(9)); - assertEquals("13 key M0 [B]", 0, params.getColumnPos(10)); - assertEquals("13 key M0 [C]", 1, params.getColumnPos(11)); - assertEquals("13 key M0 [D]", -1, params.getColumnPos(12)); - assertEquals("13 key M0 adjust", 0, params.mTopRowAdjustment); - assertEquals("13 key M0 default", WIDTH * 2, params.getDefaultKeyCoordX()); - } -} diff --git a/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderTests.java b/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderTests.java new file mode 100644 index 000000000..1a1d643fd --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderTests.java @@ -0,0 +1,1616 @@ +/* + * 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; + +import android.test.AndroidTestCase; + +import com.android.inputmethod.keyboard.MoreKeysKeyboard.Builder.MoreKeysKeyboardParams; + +public class MoreKeysKeyboardBuilderTests extends AndroidTestCase { + private static final int WIDTH = 10; + private static final int HEIGHT = 10; + + private static final int KEYBOARD_WIDTH = WIDTH * 10; + private static final int XPOS_L0 = WIDTH * 0 + WIDTH / 2; + private static final int XPOS_L1 = WIDTH * 1 + WIDTH / 2; + private static final int XPOS_L2 = WIDTH * 2 + WIDTH / 2; + private static final int XPOS_L3 = WIDTH * 3 + WIDTH / 2; + private static final int XPOS_M0 = WIDTH * 4 + WIDTH / 2; + private static final int XPOS_M1 = WIDTH * 5 + WIDTH / 2; + private static final int XPOS_R3 = WIDTH * 6 + WIDTH / 2; + private static final int XPOS_R2 = WIDTH * 7 + WIDTH / 2; + private static final int XPOS_R1 = WIDTH * 8 + WIDTH / 2; + private static final int XPOS_R0 = WIDTH * 9 + WIDTH / 2; + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + private static MoreKeysKeyboardParams createParams(int numKeys, int maxColumns, + int coordXInParnet) { + return new MoreKeysKeyboardParams(numKeys, maxColumns, WIDTH, HEIGHT, coordXInParnet, + KEYBOARD_WIDTH); + } + + public void testLayoutError() { + MoreKeysKeyboardParams params = null; + try { + final int maxColumns = KEYBOARD_WIDTH / WIDTH; + params = createParams(10, maxColumns + 1, HEIGHT); + fail("Should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // Too small keyboard to hold more keys keyboard. + } + assertNull("Too small keyboard to hold more keys keyboard", params); + } + + // More keys keyboard layout test. + // "[n]" represents n-th key position in more keys keyboard. + // "[1]" is the default key. + + // [1] + public void testLayout1KeyMax5M0() { + MoreKeysKeyboardParams params = createParams(1, 5, XPOS_M0); + assertEquals("1 key max 5 M0 columns", 1, params.mNumColumns); + assertEquals("1 key max 5 M0 rows", 1, params.mNumRows); + assertEquals("1 key max 5 M0 left", 0, params.mLeftKeys); + assertEquals("1 key max 5 M0 right", 1, params.mRightKeys); + assertEquals("1 key max 5 M0 [1]", 0, params.getColumnPos(0)); + assertEquals("1 key max 5 M0 adjust", 0, params.mTopRowAdjustment); + assertEquals("1 key max 5 M0 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |[1] + public void testLayout1KeyMax5L0() { + MoreKeysKeyboardParams params = createParams(1, 5, XPOS_L0); + assertEquals("1 key max 5 L0 columns", 1, params.mNumColumns); + assertEquals("1 key max 5 L0 rows", 1, params.mNumRows); + assertEquals("1 key max 5 L0 left", 0, params.mLeftKeys); + assertEquals("1 key max 5 L0 right", 1, params.mRightKeys); + assertEquals("1 key max 5 L0 [1]", 0, params.getColumnPos(0)); + assertEquals("1 key max 5 L0 adjust", 0, params.mTopRowAdjustment); + assertEquals("1 key max 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [1] + public void testLayout1KeyMax5L1() { + MoreKeysKeyboardParams params = createParams(1, 5, XPOS_L1); + assertEquals("1 key max 5 L1 columns", 1, params.mNumColumns); + assertEquals("1 key max 5 L1 rows", 1, params.mNumRows); + assertEquals("1 key max 5 L1 left", 0, params.mLeftKeys); + assertEquals("1 key max 5 L1 right", 1, params.mRightKeys); + assertEquals("1 key max 5 L1 [1]", 0, params.getColumnPos(0)); + assertEquals("1 key max 5 L1 adjust", 0, params.mTopRowAdjustment); + assertEquals("1 key max 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ ___ [1] + public void testLayout1KeyMax5L2() { + MoreKeysKeyboardParams params = createParams(1, 5, XPOS_L2); + assertEquals("1 key max 5 L2 columns", 1, params.mNumColumns); + assertEquals("1 key max 5 L2 rows", 1, params.mNumRows); + assertEquals("1 key max 5 L2 left", 0, params.mLeftKeys); + assertEquals("1 key max 5 L2 right", 1, params.mRightKeys); + assertEquals("1 key max 5 L2 [1]", 0, params.getColumnPos(0)); + assertEquals("1 key max 5 L2 adjust", 0, params.mTopRowAdjustment); + assertEquals("1 key max 5 L2 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // [1]| + public void testLayout1KeyMax5R0() { + MoreKeysKeyboardParams params = createParams(1, 5, XPOS_R0); + assertEquals("1 key max 5 R0 columns", 1, params.mNumColumns); + assertEquals("1 key max 5 R0 rows", 1, params.mNumRows); + assertEquals("1 key max 5 R0 left", 0, params.mLeftKeys); + assertEquals("1 key max 5 R0 right", 1, params.mRightKeys); + assertEquals("1 key max 5 R0 [1]", 0, params.getColumnPos(0)); + assertEquals("1 key max 5 R0 adjust", 0, params.mTopRowAdjustment); + assertEquals("1 key max 5 R0 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // [1] ___| + public void testLayout1KeyMax5R1() { + MoreKeysKeyboardParams params = createParams(1, 5, XPOS_R1); + assertEquals("1 key max 5 R1 columns", 1, params.mNumColumns); + assertEquals("1 key max 5 R1 rows", 1, params.mNumRows); + assertEquals("1 key max 5 R1 left", 0, params.mLeftKeys); + assertEquals("1 key max 5 R1 right", 1, params.mRightKeys); + assertEquals("1 key max 5 R1 [1]", 0, params.getColumnPos(0)); + assertEquals("1 key max 5 R1 adjust", 0, params.mTopRowAdjustment); + assertEquals("1 key max 5 R1 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // [1] ___ ___| + public void testLayout1KeyMax5R2() { + MoreKeysKeyboardParams params = createParams(1, 5, XPOS_R2); + assertEquals("1 key max 5 R2 columns", 1, params.mNumColumns); + assertEquals("1 key max 5 R2 rows", 1, params.mNumRows); + assertEquals("1 key max 5 R2 left", 0, params.mLeftKeys); + assertEquals("1 key max 5 R2 right", 1, params.mRightKeys); + assertEquals("1 key max 5 R2 [1]", 0, params.getColumnPos(0)); + assertEquals("1 key max 5 R2 adjust", 0, params.mTopRowAdjustment); + assertEquals("1 key max 5 R2 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // [1] [2] + public void testLayout2KeyMax5M0() { + MoreKeysKeyboardParams params = createParams(2, 5, XPOS_M0); + assertEquals("2 key max 5 M0 columns", 2, params.mNumColumns); + assertEquals("2 key max 5 M0 rows", 1, params.mNumRows); + assertEquals("2 key max 5 M0 left", 0, params.mLeftKeys); + assertEquals("2 key max 5 M0 right", 2, params.mRightKeys); + assertEquals("2 key max 5 M0 [1]", 0, params.getColumnPos(0)); + assertEquals("2 key max 5 M0 [2]", 1, params.getColumnPos(1)); + assertEquals("2 key max 5 M0 adjust", 0, params.mTopRowAdjustment); + assertEquals("2 key max 5 M0 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |[1] [2] + public void testLayout2KeyMax5L0() { + MoreKeysKeyboardParams params = createParams(2, 5, XPOS_L0); + assertEquals("2 key max 5 L0 columns", 2, params.mNumColumns); + assertEquals("2 key max 5 L0 rows", 1, params.mNumRows); + assertEquals("2 key max 5 L0 left", 0, params.mLeftKeys); + assertEquals("2 key max 5 L0 right", 2, params.mRightKeys); + assertEquals("2 key max 5 L0 [1]", 0, params.getColumnPos(0)); + assertEquals("2 key max 5 L0 [2]", 1, params.getColumnPos(1)); + assertEquals("2 key max 5 L0 adjust", 0, params.mTopRowAdjustment); + assertEquals("2 key max 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [1] [2] + public void testLayout2KeyMax5L1() { + MoreKeysKeyboardParams params = createParams(2, 5, XPOS_L1); + assertEquals("2 key max 5 L1 columns", 2, params.mNumColumns); + assertEquals("2 key max 5 L1 rows", 1, params.mNumRows); + assertEquals("2 key max 5 L1 left", 0, params.mLeftKeys); + assertEquals("2 key max 5 L1 right", 2, params.mRightKeys); + assertEquals("2 key max 5 L1 [1]", 0, params.getColumnPos(0)); + assertEquals("2 key max 5 L1 [2]", 1, params.getColumnPos(1)); + assertEquals("2 key max 5 L1 adjust", 0, params.mTopRowAdjustment); + assertEquals("2 key max 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ ___ [1] [2] + public void testLayout2KeyMax5L2() { + MoreKeysKeyboardParams params = createParams(2, 5, XPOS_L2); + assertEquals("2 key max 5 L2 columns", 2, params.mNumColumns); + assertEquals("2 key max 5 L2 rows", 1, params.mNumRows); + assertEquals("2 key max 5 L2 left", 0, params.mLeftKeys); + assertEquals("2 key max 5 L2 right", 2, params.mRightKeys); + assertEquals("2 key max 5 L2 [1]", 0, params.getColumnPos(0)); + assertEquals("2 key max 5 L2 [2]", 1, params.getColumnPos(1)); + assertEquals("2 key max 5 L2 adjust", 0, params.mTopRowAdjustment); + assertEquals("2 key max 5 L2 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // [2] [1]| + public void testLayout2KeyMax5R0() { + MoreKeysKeyboardParams params = createParams(2, 5, XPOS_R0); + assertEquals("2 key max 5 R0 columns", 2, params.mNumColumns); + assertEquals("2 key max 5 R0 rows", 1, params.mNumRows); + assertEquals("2 key max 5 R0 left", 1, params.mLeftKeys); + assertEquals("2 key max 5 R0 right", 1, params.mRightKeys); + assertEquals("2 key max 5 R0 [1]", 0, params.getColumnPos(0)); + assertEquals("2 key max 5 R0 [2]", -1, params.getColumnPos(1)); + assertEquals("2 key max 5 R0 adjust", 0, params.mTopRowAdjustment); + assertEquals("2 key max 5 R0 default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // [2] [1] ___| + public void testLayout2KeyMax5R1() { + MoreKeysKeyboardParams params = createParams(2, 5, XPOS_R1); + assertEquals("2 key max 5 R1 columns", 2, params.mNumColumns); + assertEquals("2 key max 5 R1 rows", 1, params.mNumRows); + assertEquals("2 key max 5 R1 left", 1, params.mLeftKeys); + assertEquals("2 key max 5 R1 right", 1, params.mRightKeys); + assertEquals("2 key max 5 R1 [1]", 0, params.getColumnPos(0)); + assertEquals("2 key max 5 R1 [2]", -1, params.getColumnPos(1)); + assertEquals("2 key max 5 R1 adjust", 0, params.mTopRowAdjustment); + assertEquals("2 key max 5 R1 default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // [1] [2] ___| + public void testLayout2KeyMax5R2() { + MoreKeysKeyboardParams params = createParams(2, 5, XPOS_R2); + assertEquals("2 key max 5 R2 columns", 2, params.mNumColumns); + assertEquals("2 key max 5 R2 rows", 1, params.mNumRows); + assertEquals("2 key max 5 R2 left", 0, params.mLeftKeys); + assertEquals("2 key max 5 R2 right", 2, params.mRightKeys); + assertEquals("2 key max 5 R2 [1]", 0, params.getColumnPos(0)); + assertEquals("2 key max 5 R2 [2]", 1, params.getColumnPos(1)); + assertEquals("2 key max 5 R2 adjust", 0, params.mTopRowAdjustment); + assertEquals("2 key max 5 R2 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // [3] [1] [2] + public void testLayout3KeyMax5M0() { + MoreKeysKeyboardParams params = createParams(3, 5, XPOS_M0); + assertEquals("3 key columns", 3, params.mNumColumns); + assertEquals("3 key rows", 1, params.mNumRows); + assertEquals("3 key left", 1, params.mLeftKeys); + assertEquals("3 key right", 2, params.mRightKeys); + assertEquals("3 key [1]", 0, params.getColumnPos(0)); + assertEquals("3 key [2]", 1, params.getColumnPos(1)); + assertEquals("3 key [3]", -1, params.getColumnPos(2)); + assertEquals("3 key adjust", 0, params.mTopRowAdjustment); + assertEquals("3 key default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // |[1] [2] [3] + public void testLayout3KeyMax5L0() { + MoreKeysKeyboardParams params = createParams(3, 5, XPOS_L0); + assertEquals("3 key max 5 L0 columns", 3, params.mNumColumns); + assertEquals("3 key max 5 L0 rows", 1, params.mNumRows); + assertEquals("3 key max 5 L0 left", 0, params.mLeftKeys); + assertEquals("3 key max 5 L0 right", 3, params.mRightKeys); + assertEquals("3 key max 5 L0 [1]", 0, params.getColumnPos(0)); + assertEquals("3 key max 5 L0 [2]", 1, params.getColumnPos(1)); + assertEquals("3 key max 5 L0 [3]", 2, params.getColumnPos(2)); + assertEquals("3 key max 5 L0 adjust", 0, params.mTopRowAdjustment); + assertEquals("3 key max 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [1] [2] [3] + public void testLayout3KeyMax5L1() { + MoreKeysKeyboardParams params = createParams(3, 5, XPOS_L1); + assertEquals("3 key max 5 L1 columns", 3, params.mNumColumns); + assertEquals("3 key max 5 L1 rows", 1, params.mNumRows); + assertEquals("3 key max 5 L1 left", 0, params.mLeftKeys); + assertEquals("3 key max 5 L1 right", 3, params.mRightKeys); + assertEquals("3 key max 5 L1 [1]", 0, params.getColumnPos(0)); + assertEquals("3 key max 5 L1 [2]", 1, params.getColumnPos(1)); + assertEquals("3 key max 5 L1 [3]", 2, params.getColumnPos(2)); + assertEquals("3 key max 5 L1 adjust", 0, params.mTopRowAdjustment); + assertEquals("3 key max 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [3] [1] [2] + public void testLayout3KeyMax5L2() { + MoreKeysKeyboardParams params = createParams(3, 5, XPOS_L2); + assertEquals("3 key max 5 L2 columns", 3, params.mNumColumns); + assertEquals("3 key max 5 L2 rows", 1, params.mNumRows); + assertEquals("3 key max 5 L2 left", 1, params.mLeftKeys); + assertEquals("3 key max 5 L2 right", 2, params.mRightKeys); + assertEquals("3 key max 5 L2 [1]", 0, params.getColumnPos(0)); + assertEquals("3 key max 5 L2 [2]", 1, params.getColumnPos(1)); + assertEquals("3 key max 5 L2 [3]", -1, params.getColumnPos(2)); + assertEquals("3 key max 5 L2 adjust", 0, params.mTopRowAdjustment); + assertEquals("3 key max 5 L2 default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // [3] [2] [1]| + public void testLayout3KeyMax5R0() { + MoreKeysKeyboardParams params = createParams(3, 5, XPOS_R0); + assertEquals("3 key max 5 R0 columns", 3, params.mNumColumns); + assertEquals("3 key max 5 R0 rows", 1, params.mNumRows); + assertEquals("3 key max 5 R0 left", 2, params.mLeftKeys); + assertEquals("3 key max 5 R0 right", 1, params.mRightKeys); + assertEquals("3 key max 5 R0 [1]", 0, params.getColumnPos(0)); + assertEquals("3 key max 5 R0 [2]", -1, params.getColumnPos(1)); + assertEquals("3 key max 5 R0 [3]", -2, params.getColumnPos(2)); + assertEquals("3 key max 5 R0 adjust", 0, params.mTopRowAdjustment); + assertEquals("3 key max 5 R0 default", WIDTH * 2, params.getDefaultKeyCoordX()); + } + + // [3] [2] [1] ___| + public void testLayout3KeyMax5R1() { + MoreKeysKeyboardParams params = createParams(3, 5, XPOS_R1); + assertEquals("3 key max 5 R1 columns", 3, params.mNumColumns); + assertEquals("3 key max 5 R1 rows", 1, params.mNumRows); + assertEquals("3 key max 5 R1 left", 2, params.mLeftKeys); + assertEquals("3 key max 5 R1 right", 1, params.mRightKeys); + assertEquals("3 key max 5 R1 [1]", 0, params.getColumnPos(0)); + assertEquals("3 key max 5 R1 [2]", -1, params.getColumnPos(1)); + assertEquals("3 key max 5 R1 [3]", -2, params.getColumnPos(2)); + assertEquals("3 key max 5 R1 adjust", 0, params.mTopRowAdjustment); + assertEquals("3 key max 5 R1 default", WIDTH * 2, params.getDefaultKeyCoordX()); + } + + // [3] [1] [2] ___| + public void testLayout3KeyMax5R2() { + MoreKeysKeyboardParams params = createParams(3, 5, XPOS_R2); + assertEquals("3 key max 5 R2 columns", 3, params.mNumColumns); + assertEquals("3 key max 5 R2 rows", 1, params.mNumRows); + assertEquals("3 key max 5 R2 left", 1, params.mLeftKeys); + assertEquals("3 key max 5 R2 right", 2, params.mRightKeys); + assertEquals("3 key max 5 R2 [1]", 0, params.getColumnPos(0)); + assertEquals("3 key max 5 R2 [2]", 1, params.getColumnPos(1)); + assertEquals("3 key max 5 R2 [3]", -1, params.getColumnPos(2)); + assertEquals("3 key max 5 R2 adjust", 0, params.mTopRowAdjustment); + assertEquals("3 key max 5 R2 default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // [3] + // [1] [2] + public void testLayout3KeyMax2M0() { + MoreKeysKeyboardParams params = createParams(3, 2, XPOS_M0); + assertEquals("3 key max 2 columns", 2, params.mNumColumns); + assertEquals("3 key max 2 rows", 2, params.mNumRows); + assertEquals("3 key max 2 left", 0, params.mLeftKeys); + assertEquals("3 key max 2 right", 2, params.mRightKeys); + assertEquals("3 key max 2 [1]", 0, params.getColumnPos(0)); + assertEquals("3 key max 2 [2]", 1, params.getColumnPos(1)); + assertEquals("3 key max 2 [3]", 0, params.getColumnPos(2)); + assertEquals("3 key max 2 adjust", 1, params.mTopRowAdjustment); + assertEquals("3 key max 2 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // | [3] + // |[1] [2] + public void testLayout3KeyMax2L0() { + MoreKeysKeyboardParams params = createParams(3, 2, XPOS_L0); + assertEquals("3 key max 2 L0 columns", 2, params.mNumColumns); + assertEquals("3 key max 2 L0 rows", 2, params.mNumRows); + assertEquals("3 key max 2 L0 left", 0, params.mLeftKeys); + assertEquals("3 key max 2 L0 right", 2, params.mRightKeys); + assertEquals("3 key max 2 L0 [1]", 0, params.getColumnPos(0)); + assertEquals("3 key max 2 L0 [2]", 1, params.getColumnPos(1)); + assertEquals("3 key max 2 L0 [3]", 0, params.getColumnPos(2)); + assertEquals("3 key max 2 L0 adjust", 1, params.mTopRowAdjustment); + assertEquals("3 key max 2 L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [3] + // |___ [1] [2] + public void testLayout3KeyMax2L1() { + MoreKeysKeyboardParams params = createParams(3, 2, XPOS_L1); + assertEquals("3 key max 2 L1 columns", 2, params.mNumColumns); + assertEquals("3 key max 2 L1 rows", 2, params.mNumRows); + assertEquals("3 key max 2 L1 left", 0, params.mLeftKeys); + assertEquals("3 key max 2 L1 right", 2, params.mRightKeys); + assertEquals("3 key max 2 L1 [1]", 0, params.getColumnPos(0)); + assertEquals("3 key max 2 L1 [2]", 1, params.getColumnPos(1)); + assertEquals("3 key max 2 L1 [3]", 0, params.getColumnPos(2)); + assertEquals("3 key max 2 L1 adjust", 1, params.mTopRowAdjustment); + assertEquals("3 key max 2 L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // | [3] + // |___ ___ [1] [2] + public void testLayout3KeyMax2L2() { + MoreKeysKeyboardParams params = createParams(3, 2, XPOS_L2); + assertEquals("3 key max 2 L2 columns", 2, params.mNumColumns); + assertEquals("3 key max 2 L2 rows", 2, params.mNumRows); + assertEquals("3 key max 2 L2 left", 0, params.mLeftKeys); + assertEquals("3 key max 2 L2 right", 2, params.mRightKeys); + assertEquals("3 key max 2 L2 [1]", 0, params.getColumnPos(0)); + assertEquals("3 key max 2 L2 [2]", 1, params.getColumnPos(1)); + assertEquals("3 key max 2 L2 [3]", 0, params.getColumnPos(2)); + assertEquals("3 key max 2 L2 adjust", 1, params.mTopRowAdjustment); + assertEquals("3 key max 2 L2 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // [3] | + // [2] [1]| + public void testLayout3KeyMax2R0() { + MoreKeysKeyboardParams params = createParams(3, 2, XPOS_R0); + assertEquals("3 key max 2 R0 columns", 2, params.mNumColumns); + assertEquals("3 key max 2 R0 rows", 2, params.mNumRows); + assertEquals("3 key max 2 R0 left", 1, params.mLeftKeys); + assertEquals("3 key max 2 R0 right", 1, params.mRightKeys); + assertEquals("3 key max 2 R0 [1]", 0, params.getColumnPos(0)); + assertEquals("3 key max 2 R0 [2]", -1, params.getColumnPos(1)); + assertEquals("3 key max 2 R0 [3]", 0, params.getColumnPos(2)); + assertEquals("3 key max 2 R0 adjust", -1, params.mTopRowAdjustment); + assertEquals("3 key max 2 R0 default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // [3] | + // [2] [1] ___| + public void testLayout3KeyMax2R1() { + MoreKeysKeyboardParams params = createParams(3, 2, XPOS_R1); + assertEquals("3 key max 2 R1 columns", 2, params.mNumColumns); + assertEquals("3 key max 2 R1 rows", 2, params.mNumRows); + assertEquals("3 key max 2 R1 left", 1, params.mLeftKeys); + assertEquals("3 key max 2 R1 right", 1, params.mRightKeys); + assertEquals("3 key max 2 R1 [1]", 0, params.getColumnPos(0)); + assertEquals("3 key max 2 R1 [2]", -1, params.getColumnPos(1)); + assertEquals("3 key max 2 R1 [3]", 0, params.getColumnPos(2)); + assertEquals("3 key max 2 R1 adjust", -1, params.mTopRowAdjustment); + assertEquals("3 key max 2 R1 default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // [3] | + // [1] [2] ___| + public void testLayout3KeyMax2R2() { + MoreKeysKeyboardParams params = createParams(3, 2, XPOS_R2); + assertEquals("3 key max 2 R2 columns", 2, params.mNumColumns); + assertEquals("3 key max 2 R2 rows", 2, params.mNumRows); + assertEquals("3 key max 2 R2 left", 0, params.mLeftKeys); + assertEquals("3 key max 2 R2 right", 2, params.mRightKeys); + assertEquals("3 key max 2 R2 [1]", 0, params.getColumnPos(0)); + assertEquals("3 key max 2 R2 [2]", 1, params.getColumnPos(1)); + assertEquals("3 key max 2 R2 [3]", 0, params.getColumnPos(2)); + assertEquals("3 key max 2 R2 adjust", 1, params.mTopRowAdjustment); + assertEquals("3 key max 2 R2 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // [3] [1] [2] [4] + public void testLayout4KeyMax5M0() { + MoreKeysKeyboardParams params = createParams(4, 5, XPOS_M0); + assertEquals("4 key columns", 4, params.mNumColumns); + assertEquals("4 key rows", 1, params.mNumRows); + assertEquals("4 key left", 1, params.mLeftKeys); + assertEquals("4 key right", 3, params.mRightKeys); + assertEquals("4 key [1]", 0, params.getColumnPos(0)); + assertEquals("4 key [2]", 1, params.getColumnPos(1)); + assertEquals("4 key [3]", -1, params.getColumnPos(2)); + assertEquals("4 key [4]", 2, params.getColumnPos(3)); + assertEquals("4 key adjust", 0, params.mTopRowAdjustment); + assertEquals("4 key default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // |[1] [2] [3] [4] + public void testLayout4KeyMax5L0() { + MoreKeysKeyboardParams params = createParams(4, 5, XPOS_L0); + assertEquals("4 key max 5 L0 columns", 4, params.mNumColumns); + assertEquals("4 key max 5 L0 rows", 1, params.mNumRows); + assertEquals("4 key max 5 L0 left", 0, params.mLeftKeys); + assertEquals("4 key max 5 L0 right", 4, params.mRightKeys); + assertEquals("4 key max 5 L0 [1]", 0, params.getColumnPos(0)); + assertEquals("4 key max 5 L0 [2]", 1, params.getColumnPos(1)); + assertEquals("4 key max 5 L0 [3]", 2, params.getColumnPos(2)); + assertEquals("4 key max 5 L0 [4]", 3, params.getColumnPos(3)); + assertEquals("4 key max 5 L0 adjust", 0, params.mTopRowAdjustment); + assertEquals("4 key max 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [1] [2] [3] [4] + public void testLayout4KeyMax5L1() { + MoreKeysKeyboardParams params = createParams(4, 5, XPOS_L1); + assertEquals("4 key max 5 L1 columns", 4, params.mNumColumns); + assertEquals("4 key max 5 L1 rows", 1, params.mNumRows); + assertEquals("4 key max 5 L1 left", 0, params.mLeftKeys); + assertEquals("4 key max 5 L1 right", 4, params.mRightKeys); + assertEquals("4 key max 5 L1 [1]", 0, params.getColumnPos(0)); + assertEquals("4 key max 5 L1 [2]", 1, params.getColumnPos(1)); + assertEquals("4 key max 5 L1 [3]", 2, params.getColumnPos(2)); + assertEquals("4 key max 5 L1 [4]", 3, params.getColumnPos(3)); + assertEquals("4 key max 5 L1 adjust", 0, params.mTopRowAdjustment); + assertEquals("4 key max 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [3] [1] [2] [4] + public void testLayout4KeyMax5L2() { + MoreKeysKeyboardParams params = createParams(4, 5, XPOS_L2); + assertEquals("4 key max 5 L2 columns", 4, params.mNumColumns); + assertEquals("4 key max 5 L2 rows", 1, params.mNumRows); + assertEquals("4 key max 5 L2 left", 1, params.mLeftKeys); + assertEquals("4 key max 5 L2 right", 3, params.mRightKeys); + assertEquals("4 key max 5 L2 [1]", 0, params.getColumnPos(0)); + assertEquals("4 key max 5 L2 [2]", 1, params.getColumnPos(1)); + assertEquals("4 key max 5 L2 [3]", -1, params.getColumnPos(2)); + assertEquals("4 key max 5 L2 [4]", 2, params.getColumnPos(3)); + assertEquals("4 key max 5 L2 adjust", 0, params.mTopRowAdjustment); + assertEquals("4 key max 5 L2 default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // [4] [3] [2] [1]| + public void testLayout4KeyMax5R0() { + MoreKeysKeyboardParams params = createParams(4, 5, XPOS_R0); + assertEquals("4 key max 5 R0 columns", 4, params.mNumColumns); + assertEquals("4 key max 5 R0 rows", 1, params.mNumRows); + assertEquals("4 key max 5 R0 left", 3, params.mLeftKeys); + assertEquals("4 key max 5 R0 right", 1, params.mRightKeys); + assertEquals("4 key max 5 R0 [1]", 0, params.getColumnPos(0)); + assertEquals("4 key max 5 R0 [2]", -1, params.getColumnPos(1)); + assertEquals("4 key max 5 R0 [3]", -2, params.getColumnPos(2)); + assertEquals("4 key max 5 R0 [4]", -3, params.getColumnPos(3)); + assertEquals("4 key max 5 R0 adjust", 0, params.mTopRowAdjustment); + assertEquals("4 key max 5 R0 default", WIDTH * 3, params.getDefaultKeyCoordX()); + } + + // [4] [3] [2] [1] ___| + public void testLayout4KeyMax5R1() { + MoreKeysKeyboardParams params = createParams(4, 5, XPOS_R1); + assertEquals("4 key max 5 R1 columns", 4, params.mNumColumns); + assertEquals("4 key max 5 R1 rows", 1, params.mNumRows); + assertEquals("4 key max 5 R1 left", 3, params.mLeftKeys); + assertEquals("4 key max 5 R1 right", 1, params.mRightKeys); + assertEquals("4 key max 5 R1 [1]", 0, params.getColumnPos(0)); + assertEquals("4 key max 5 R1 [2]", -1, params.getColumnPos(1)); + assertEquals("4 key max 5 R1 [3]", -2, params.getColumnPos(2)); + assertEquals("4 key max 5 R1 [4]", -3, params.getColumnPos(3)); + assertEquals("4 key max 5 R1 adjust", 0, params.mTopRowAdjustment); + assertEquals("4 key max 5 R1 default", WIDTH * 3, params.getDefaultKeyCoordX()); + } + + // [4] [3] [1] [2] ___| + public void testLayout4KeyMax5R2() { + MoreKeysKeyboardParams params = createParams(4, 5, XPOS_R2); + assertEquals("4 key max 5 R2 columns", 4, params.mNumColumns); + assertEquals("4 key max 5 R2 rows", 1, params.mNumRows); + assertEquals("4 key max 5 R2 left", 2, params.mLeftKeys); + assertEquals("4 key max 5 R2 right", 2, params.mRightKeys); + assertEquals("4 key max 5 R2 [1]", 0, params.getColumnPos(0)); + assertEquals("4 key max 5 R2 [2]", 1, params.getColumnPos(1)); + assertEquals("4 key max 5 R2 [3]", -1, params.getColumnPos(2)); + assertEquals("4 key max 5 R2 [4]", -2, params.getColumnPos(3)); + assertEquals("4 key max 5 R2 adjust", 0, params.mTopRowAdjustment); + assertEquals("4 key max 5 R2 default", WIDTH * 2, params.getDefaultKeyCoordX()); + } + + // [5] [3] [1] [2] [4] + public void testLayout5KeyMax5M0() { + MoreKeysKeyboardParams params = createParams(5, 5, XPOS_M0); + assertEquals("5 key columns", 5, params.mNumColumns); + assertEquals("5 key rows", 1, params.mNumRows); + assertEquals("5 key left", 2, params.mLeftKeys); + assertEquals("5 key right", 3, params.mRightKeys); + assertEquals("5 key [1]", 0, params.getColumnPos(0)); + assertEquals("5 key [2]", 1, params.getColumnPos(1)); + assertEquals("5 key [3]", -1, params.getColumnPos(2)); + assertEquals("5 key [4]", 2, params.getColumnPos(3)); + assertEquals("5 key [5]", -2, params.getColumnPos(4)); + assertEquals("5 key adjust", 0, params.mTopRowAdjustment); + assertEquals("5 key default", WIDTH * 2, params.getDefaultKeyCoordX()); + } + + // |[1] [2] [3] [4] [5] + public void testLayout5KeyMax5L0() { + MoreKeysKeyboardParams params = createParams(5, 5, XPOS_L0); + assertEquals("5 key max 5 L0 columns", 5, params.mNumColumns); + assertEquals("5 key max 5 L0 rows", 1, params.mNumRows); + assertEquals("5 key max 5 L0 left", 0, params.mLeftKeys); + assertEquals("5 key max 5 L0 right", 5, params.mRightKeys); + assertEquals("5 key max 5 L0 [1]", 0, params.getColumnPos(0)); + assertEquals("5 key max 5 L0 [2]", 1, params.getColumnPos(1)); + assertEquals("5 key max 5 L0 [3]", 2, params.getColumnPos(2)); + assertEquals("5 key max 5 L0 [4]", 3, params.getColumnPos(3)); + assertEquals("5 key max 5 L0 [5]", 4, params.getColumnPos(4)); + assertEquals("5 key max 5 L0 adjust", 0, params.mTopRowAdjustment); + assertEquals("5 key max 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [1] [2] [3] [4] [5] + public void testLayout5KeyMax5L1() { + MoreKeysKeyboardParams params = createParams(5, 5, XPOS_L1); + assertEquals("5 key max 5 L1 columns", 5, params.mNumColumns); + assertEquals("5 key max 5 L1 rows", 1, params.mNumRows); + assertEquals("5 key max 5 L1 left", 0, params.mLeftKeys); + assertEquals("5 key max 5 L1 right", 5, params.mRightKeys); + assertEquals("5 key max 5 L1 [1]", 0, params.getColumnPos(0)); + assertEquals("5 key max 5 L1 [2]", 1, params.getColumnPos(1)); + assertEquals("5 key max 5 L1 [3]", 2, params.getColumnPos(2)); + assertEquals("5 key max 5 L1 [4]", 3, params.getColumnPos(3)); + assertEquals("5 key max 5 L1 [5]", 4, params.getColumnPos(4)); + assertEquals("5 key max 5 L1 adjust", 0, params.mTopRowAdjustment); + assertEquals("5 key max 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [3] [1] [2] [4] [5] + public void testLayout5KeyMax5L2() { + MoreKeysKeyboardParams params = createParams(5, 5, XPOS_L2); + assertEquals("5 key max 5 L2 columns", 5, params.mNumColumns); + assertEquals("5 key max 5 L2 rows", 1, params.mNumRows); + assertEquals("5 key max 5 L2 left", 1, params.mLeftKeys); + assertEquals("5 key max 5 L2 right", 4, params.mRightKeys); + assertEquals("5 key max 5 L2 [1]", 0, params.getColumnPos(0)); + assertEquals("5 key max 5 L2 [2]", 1, params.getColumnPos(1)); + assertEquals("5 key max 5 L2 [3]", -1, params.getColumnPos(2)); + assertEquals("5 key max 5 L2 [4]", 2, params.getColumnPos(3)); + assertEquals("5 key max 5 L2 [5]", 3, params.getColumnPos(4)); + assertEquals("5 key max 5 L2 adjust", 0, params.mTopRowAdjustment); + assertEquals("5 key max 5 L2 default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // [5] [4] [3] [2] [1]| + public void testLayout5KeyMax5R0() { + MoreKeysKeyboardParams params = createParams(5, 5, XPOS_R0); + assertEquals("5 key max 5 R0 columns", 5, params.mNumColumns); + assertEquals("5 key max 5 R0 rows", 1, params.mNumRows); + assertEquals("5 key max 5 R0 left", 4, params.mLeftKeys); + assertEquals("5 key max 5 R0 right", 1, params.mRightKeys); + assertEquals("5 key max 5 R0 [1]", 0, params.getColumnPos(0)); + assertEquals("5 key max 5 R0 [2]", -1, params.getColumnPos(1)); + assertEquals("5 key max 5 R0 [3]", -2, params.getColumnPos(2)); + assertEquals("5 key max 5 R0 [4]", -3, params.getColumnPos(3)); + assertEquals("5 key max 5 R0 [5]", -4, params.getColumnPos(4)); + assertEquals("5 key max 5 R0 adjust", 0, params.mTopRowAdjustment); + assertEquals("5 key max 5 R0 default", WIDTH * 4, params.getDefaultKeyCoordX()); + } + + // [5] [4] [3] [2] [1] ___| + public void testLayout5KeyMax5R1() { + MoreKeysKeyboardParams params = createParams(5, 5, XPOS_R1); + assertEquals("5 key max 5 R1 columns", 5, params.mNumColumns); + assertEquals("5 key max 5 R1 rows", 1, params.mNumRows); + assertEquals("5 key max 5 R1 left", 4, params.mLeftKeys); + assertEquals("5 key max 5 R1 right", 1, params.mRightKeys); + assertEquals("5 key max 5 R1 [1]", 0, params.getColumnPos(0)); + assertEquals("5 key max 5 R1 [2]", -1, params.getColumnPos(1)); + assertEquals("5 key max 5 R1 [3]", -2, params.getColumnPos(2)); + assertEquals("5 key max 5 R1 [4]", -3, params.getColumnPos(3)); + assertEquals("5 key max 5 R1 [5]", -4, params.getColumnPos(4)); + assertEquals("5 key max 5 R1 adjust", 0, params.mTopRowAdjustment); + assertEquals("5 key max 5 R1 default", WIDTH * 4, params.getDefaultKeyCoordX()); + } + + // [5] [4] [3] [1] [2] ___| + public void testLayout5KeyMax5R2() { + MoreKeysKeyboardParams params = createParams(5, 5, XPOS_R2); + assertEquals("5 key max 5 R2 columns", 5, params.mNumColumns); + assertEquals("5 key max 5 R2 rows", 1, params.mNumRows); + assertEquals("5 key max 5 R2 left", 3, params.mLeftKeys); + assertEquals("5 key max 5 R2 right", 2, params.mRightKeys); + assertEquals("5 key max 5 R2 [1]", 0, params.getColumnPos(0)); + assertEquals("5 key max 5 R2 [2]", 1, params.getColumnPos(1)); + assertEquals("5 key max 5 R2 [3]", -1, params.getColumnPos(2)); + assertEquals("5 key max 5 R2 [4]", -2, params.getColumnPos(3)); + assertEquals("5 key max 5 R2 [5]", -3, params.getColumnPos(4)); + assertEquals("5 key max 5 R2 adjust", 0, params.mTopRowAdjustment); + assertEquals("5 key max 5 R2 default", WIDTH * 3, params.getDefaultKeyCoordX()); + } + + // [6] [4] [5] + // [3] [1] [2] + public void testLayout6KeyMax5M0() { + MoreKeysKeyboardParams params = createParams(6, 5, XPOS_M0); + assertEquals("6 key columns", 3, params.mNumColumns); + assertEquals("6 key rows", 2, params.mNumRows); + assertEquals("6 key left", 1, params.mLeftKeys); + assertEquals("6 key right", 2, params.mRightKeys); + assertEquals("6 key [1]", 0, params.getColumnPos(0)); + assertEquals("6 key [2]", 1, params.getColumnPos(1)); + assertEquals("6 key [3]", -1, params.getColumnPos(2)); + assertEquals("6 key [4]", 0, params.getColumnPos(3)); + assertEquals("6 key [5]", 1, params.getColumnPos(4)); + assertEquals("6 key [6]", -1, params.getColumnPos(5)); + assertEquals("6 key adjust", 0, params.mTopRowAdjustment); + assertEquals("6 key default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // |[4] [5] [6] + // |[1] [2] [3] + public void testLayout6KeyMax5L0() { + MoreKeysKeyboardParams params = createParams(6, 5, XPOS_L0); + assertEquals("6 key max 5 L0 columns", 3, params.mNumColumns); + assertEquals("6 key max 5 L0 rows", 2, params.mNumRows); + assertEquals("6 key max 5 L0 left", 0, params.mLeftKeys); + assertEquals("6 key max 5 L0 right", 3, params.mRightKeys); + assertEquals("6 key max 5 L0 [1]", 0, params.getColumnPos(0)); + assertEquals("6 key max 5 L0 [2]", 1, params.getColumnPos(1)); + assertEquals("6 key max 5 L0 [3]", 2, params.getColumnPos(2)); + assertEquals("6 key max 5 L0 [4]", 0, params.getColumnPos(3)); + assertEquals("6 key max 5 L0 [5]", 1, params.getColumnPos(4)); + assertEquals("6 key max 5 L0 [6]", 2, params.getColumnPos(5)); + assertEquals("6 key max 5 L0 adjust", 0, params.mTopRowAdjustment); + assertEquals("6 key max 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [4] [5] [6] + // |___ [1] [2] [3] + public void testLayout6KeyMax5L1() { + MoreKeysKeyboardParams params = createParams(6, 5, XPOS_L1); + assertEquals("6 key max 5 L1 columns", 3, params.mNumColumns); + assertEquals("6 key max 5 L1 rows", 2, params.mNumRows); + assertEquals("6 key max 5 L1 left", 0, params.mLeftKeys); + assertEquals("6 key max 5 L1 right", 3, params.mRightKeys); + assertEquals("6 key max 5 L1 [1]", 0, params.getColumnPos(0)); + assertEquals("6 key max 5 L1 [2]", 1, params.getColumnPos(1)); + assertEquals("6 key max 5 L1 [3]", 2, params.getColumnPos(2)); + assertEquals("6 key max 5 L1 [4]", 0, params.getColumnPos(3)); + assertEquals("6 key max 5 L1 [5]", 1, params.getColumnPos(4)); + assertEquals("6 key max 5 L1 [6]", 2, params.getColumnPos(5)); + assertEquals("6 key max 5 L1 adjust", 0, params.mTopRowAdjustment); + assertEquals("6 key max 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [6] [4] [5] + // |___ [3] [1] [2] + public void testLayout6KeyMax5L2() { + MoreKeysKeyboardParams params = createParams(6, 5, XPOS_L2); + assertEquals("6 key max 5 L2 columns", 3, params.mNumColumns); + assertEquals("6 key max 5 L2 rows", 2, params.mNumRows); + assertEquals("6 key max 5 L2 left", 1, params.mLeftKeys); + assertEquals("6 key max 5 L2 right", 2, params.mRightKeys); + assertEquals("6 key max 5 L2 [1]", 0, params.getColumnPos(0)); + assertEquals("6 key max 5 L2 [2]", 1, params.getColumnPos(1)); + assertEquals("6 key max 5 L2 [3]", -1, params.getColumnPos(2)); + assertEquals("6 key max 5 L2 [4]", 0, params.getColumnPos(3)); + assertEquals("6 key max 5 L2 [5]", 1, params.getColumnPos(4)); + assertEquals("6 key max 5 L2 [6]", -1, params.getColumnPos(5)); + assertEquals("6 key max 5 L2 adjust", 0, params.mTopRowAdjustment); + assertEquals("6 key max 5 L2 default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // [6] [5] [4]| + // [3] [2] [1]| + public void testLayout6KeyMax5R0() { + MoreKeysKeyboardParams params = createParams(6, 5, XPOS_R0); + assertEquals("6 key max 5 R0 columns", 3, params.mNumColumns); + assertEquals("6 key max 5 R0 rows", 2, params.mNumRows); + assertEquals("6 key max 5 R0 left", 2, params.mLeftKeys); + assertEquals("6 key max 5 R0 right", 1, params.mRightKeys); + assertEquals("6 key max 5 R0 [1]", 0, params.getColumnPos(0)); + assertEquals("6 key max 5 R0 [2]", -1, params.getColumnPos(1)); + assertEquals("6 key max 5 R0 [3]", -2, params.getColumnPos(2)); + assertEquals("6 key max 5 R0 [4]", 0, params.getColumnPos(3)); + assertEquals("6 key max 5 R0 [5]", -1, params.getColumnPos(4)); + assertEquals("6 key max 5 R0 [6]", -2, params.getColumnPos(5)); + assertEquals("6 key max 5 R0 adjust", 0, params.mTopRowAdjustment); + assertEquals("6 key max 5 R0 default", WIDTH * 2, params.getDefaultKeyCoordX()); + } + + // [6] [5] [4] ___| + // [3] [2] [1] ___| + public void testLayout6KeyMax5R1() { + MoreKeysKeyboardParams params = createParams(6, 5, XPOS_R1); + assertEquals("6 key max 5 R1 columns", 3, params.mNumColumns); + assertEquals("6 key max 5 R1 rows", 2, params.mNumRows); + assertEquals("6 key max 5 R1 left", 2, params.mLeftKeys); + assertEquals("6 key max 5 R1 right", 1, params.mRightKeys); + assertEquals("6 key max 5 R1 [1]", 0, params.getColumnPos(0)); + assertEquals("6 key max 5 R1 [2]", -1, params.getColumnPos(1)); + assertEquals("6 key max 5 R1 [3]", -2, params.getColumnPos(2)); + assertEquals("6 key max 5 R1 [4]", 0, params.getColumnPos(3)); + assertEquals("6 key max 5 R1 [5]", -1, params.getColumnPos(4)); + assertEquals("6 key max 5 R1 [6]", -2, params.getColumnPos(5)); + assertEquals("6 key max 5 R1 adjust", 0, params.mTopRowAdjustment); + assertEquals("6 key max 5 R1 default", WIDTH * 2, params.getDefaultKeyCoordX()); + } + + // [6] [4] [5] ___| + // [3] [1] [2] ___| + public void testLayout6KeyMax5R2() { + MoreKeysKeyboardParams params = createParams(6, 5, XPOS_R2); + assertEquals("6 key max 5 R2 columns", 3, params.mNumColumns); + assertEquals("6 key max 5 R2 rows", 2, params.mNumRows); + assertEquals("6 key max 5 R2 left", 1, params.mLeftKeys); + assertEquals("6 key max 5 R2 right", 2, params.mRightKeys); + assertEquals("6 key max 5 R2 [1]", 0, params.getColumnPos(0)); + assertEquals("6 key max 5 R2 [2]", 1, params.getColumnPos(1)); + assertEquals("6 key max 5 R2 [3]", -1, params.getColumnPos(2)); + assertEquals("6 key max 5 R2 [4]", 0, params.getColumnPos(3)); + assertEquals("6 key max 5 R2 [5]", 1, params.getColumnPos(4)); + assertEquals("6 key max 5 R2 [6]", -1, params.getColumnPos(5)); + assertEquals("6 key max 5 R2 adjust", 0, params.mTopRowAdjustment); + assertEquals("6 key max 5 R2 default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // [7] [5] [6] + // [3] [1] [2] [4] + public void testLayout7KeyMax5M0() { + MoreKeysKeyboardParams params = createParams(7, 5, XPOS_M0); + assertEquals("7 key columns", 4, params.mNumColumns); + assertEquals("7 key rows", 2, params.mNumRows); + assertEquals("7 key left", 1, params.mLeftKeys); + assertEquals("7 key right", 3, params.mRightKeys); + assertEquals("7 key [1]", 0, params.getColumnPos(0)); + assertEquals("7 key [2]", 1, params.getColumnPos(1)); + assertEquals("7 key [3]", -1, params.getColumnPos(2)); + assertEquals("7 key [4]", 2, params.getColumnPos(3)); + assertEquals("7 key [5]", 0, params.getColumnPos(4)); + assertEquals("7 key [6]", 1, params.getColumnPos(5)); + assertEquals("7 key [7]", -1, params.getColumnPos(6)); + assertEquals("7 key adjust", 1, params.mTopRowAdjustment); + assertEquals("7 key default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // | [5] [6] [7] + // |[1] [2] [3] [4] + public void testLayout7KeyMax5L0() { + MoreKeysKeyboardParams params = createParams(7, 5, XPOS_L0); + assertEquals("7 key max 5 L0 columns", 4, params.mNumColumns); + assertEquals("7 key max 5 L0 rows", 2, params.mNumRows); + assertEquals("7 key max 5 L0 left", 0, params.mLeftKeys); + assertEquals("7 key max 5 L0 right", 4, params.mRightKeys); + assertEquals("7 key max 5 L0 [1]", 0, params.getColumnPos(0)); + assertEquals("7 key max 5 L0 [2]", 1, params.getColumnPos(1)); + assertEquals("7 key max 5 L0 [3]", 2, params.getColumnPos(2)); + assertEquals("7 key max 5 L0 [4]", 3, params.getColumnPos(3)); + assertEquals("7 key max 5 L0 [5]", 0, params.getColumnPos(4)); + assertEquals("7 key max 5 L0 [6]", 1, params.getColumnPos(5)); + assertEquals("7 key max 5 L0 [7]", 2, params.getColumnPos(6)); + assertEquals("7 key max 5 L0 adjust", 1, params.mTopRowAdjustment); + assertEquals("7 key max 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [5] [6] [7] + // |___ [1] [2] [3] [4] + public void testLayout7KeyMax5L1() { + MoreKeysKeyboardParams params = createParams(7, 5, XPOS_L1); + assertEquals("7 key max 5 L1 columns", 4, params.mNumColumns); + assertEquals("7 key max 5 L1 rows", 2, params.mNumRows); + assertEquals("7 key max 5 L1 left", 0, params.mLeftKeys); + assertEquals("7 key max 5 L1 right", 4, params.mRightKeys); + assertEquals("7 key max 5 L1 [1]", 0, params.getColumnPos(0)); + assertEquals("7 key max 5 L1 [2]", 1, params.getColumnPos(1)); + assertEquals("7 key max 5 L1 [3]", 2, params.getColumnPos(2)); + assertEquals("7 key max 5 L1 [4]", 3, params.getColumnPos(3)); + assertEquals("7 key max 5 L1 [5]", 0, params.getColumnPos(4)); + assertEquals("7 key max 5 L1 [6]", 1, params.getColumnPos(5)); + assertEquals("7 key max 5 L1 [7]", 2, params.getColumnPos(6)); + assertEquals("7 key max 5 L1 adjust", 1, params.mTopRowAdjustment); + assertEquals("7 key max 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [7] [5] [6] + // |___ [3] [1] [2] [4] + public void testLayout7KeyMax5L2() { + MoreKeysKeyboardParams params = createParams(7, 5, XPOS_L2); + assertEquals("7 key max 5 L2 columns", 4, params.mNumColumns); + assertEquals("7 key max 5 L2 rows", 2, params.mNumRows); + assertEquals("7 key max 5 L2 left", 1, params.mLeftKeys); + assertEquals("7 key max 5 L2 right", 3, params.mRightKeys); + assertEquals("7 key max 5 L2 [1]", 0, params.getColumnPos(0)); + assertEquals("7 key max 5 L2 [2]", 1, params.getColumnPos(1)); + assertEquals("7 key max 5 L2 [3]", -1, params.getColumnPos(2)); + assertEquals("7 key max 5 L2 [4]", 2, params.getColumnPos(3)); + assertEquals("7 key max 5 L2 [5]", 0, params.getColumnPos(4)); + assertEquals("7 key max 5 L2 [6]", 1, params.getColumnPos(5)); + assertEquals("7 key max 5 L2 [7]", -1, params.getColumnPos(6)); + assertEquals("7 key max 5 L2 adjust", 1, params.mTopRowAdjustment); + assertEquals("7 key max 5 L2 default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // [7] [6] [5] | + // [4] [3] [2] [1]| + public void testLayout7KeyMax5R0() { + MoreKeysKeyboardParams params = createParams(7, 5, XPOS_R0); + assertEquals("7 key max 5 R0 columns", 4, params.mNumColumns); + assertEquals("7 key max 5 R0 rows", 2, params.mNumRows); + assertEquals("7 key max 5 R0 left", 3, params.mLeftKeys); + assertEquals("7 key max 5 R0 right", 1, params.mRightKeys); + assertEquals("7 key max 5 R0 [1]", 0, params.getColumnPos(0)); + assertEquals("7 key max 5 R0 [2]", -1, params.getColumnPos(1)); + assertEquals("7 key max 5 R0 [3]", -2, params.getColumnPos(2)); + assertEquals("7 key max 5 R0 [4]", -3, params.getColumnPos(3)); + assertEquals("7 key max 5 R0 [5]", 0, params.getColumnPos(4)); + assertEquals("7 key max 5 R0 [6]", -1, params.getColumnPos(5)); + assertEquals("7 key max 5 R0 [7]", -2, params.getColumnPos(6)); + assertEquals("7 key max 5 R0 adjust", -1, params.mTopRowAdjustment); + assertEquals("7 key max 5 R0 default", WIDTH * 3, params.getDefaultKeyCoordX()); + } + + // [7] [6] [5] ___| + // [4] [3] [2] [1] ___| + public void testLayout7KeyMax5R1() { + MoreKeysKeyboardParams params = createParams(7, 5, XPOS_R1); + assertEquals("7 key max 5 R1 columns", 4, params.mNumColumns); + assertEquals("7 key max 5 R1 rows", 2, params.mNumRows); + assertEquals("7 key max 5 R1 left", 3, params.mLeftKeys); + assertEquals("7 key max 5 R1 right", 1, params.mRightKeys); + assertEquals("7 key max 5 R1 [1]", 0, params.getColumnPos(0)); + assertEquals("7 key max 5 R1 [2]", -1, params.getColumnPos(1)); + assertEquals("7 key max 5 R1 [3]", -2, params.getColumnPos(2)); + assertEquals("7 key max 5 R1 [4]", -3, params.getColumnPos(3)); + assertEquals("7 key max 5 R1 [5]", 0, params.getColumnPos(4)); + assertEquals("7 key max 5 R1 [6]", -1, params.getColumnPos(5)); + assertEquals("7 key max 5 R1 [7]", -2, params.getColumnPos(6)); + assertEquals("7 key max 5 R1 adjust", -1, params.mTopRowAdjustment); + assertEquals("7 key max 5 R1 default", WIDTH * 3, params.getDefaultKeyCoordX()); + } + + // [7] [5] [6] ___| + // [4] [3] [1] [2] ___| + public void testLayout7KeyMax5R2() { + MoreKeysKeyboardParams params = createParams(7, 5, XPOS_R2); + assertEquals("7 key max 5 R2 columns", 4, params.mNumColumns); + assertEquals("7 key max 5 R2 rows", 2, params.mNumRows); + assertEquals("7 key max 5 R2 left", 2, params.mLeftKeys); + assertEquals("7 key max 5 R2 right", 2, params.mRightKeys); + assertEquals("7 key max 5 R2 [1]", 0, params.getColumnPos(0)); + assertEquals("7 key max 5 R2 [2]", 1, params.getColumnPos(1)); + assertEquals("7 key max 5 R2 [3]", -1, params.getColumnPos(2)); + assertEquals("7 key max 5 R2 [4]", -2, params.getColumnPos(3)); + assertEquals("7 key max 5 R2 [5]", 0, params.getColumnPos(4)); + assertEquals("7 key max 5 R2 [6]", 1, params.getColumnPos(5)); + assertEquals("7 key max 5 R2 [7]", -1, params.getColumnPos(6)); + assertEquals("7 key max 5 R2 adjust", -1, params.mTopRowAdjustment); + assertEquals("7 key max 5 R2 default", WIDTH * 2, params.getDefaultKeyCoordX()); + } + + // |[1] [2] [3] [4] [5] [6] [7] ___ ___ ___| + public void testLayout7KeyMax7L0() { + MoreKeysKeyboardParams params = createParams(7, 7, XPOS_L0); + assertEquals("7 key max 7 L0 columns", 7, params.mNumColumns); + assertEquals("7 key max 7 L0 rows", 1, params.mNumRows); + assertEquals("7 key max 7 L0 left", 0, params.mLeftKeys); + assertEquals("7 key max 7 L0 right", 7, params.mRightKeys); + assertEquals("7 key max 7 L0 [1]", 0, params.getColumnPos(0)); + assertEquals("7 key max 7 L0 [2]", 1, params.getColumnPos(1)); + assertEquals("7 key max 7 L0 [3]", 2, params.getColumnPos(2)); + assertEquals("7 key max 7 L0 [4]", 3, params.getColumnPos(3)); + assertEquals("7 key max 7 L0 [5]", 4, params.getColumnPos(4)); + assertEquals("7 key max 7 L0 [6]", 5, params.getColumnPos(5)); + assertEquals("7 key max 7 L0 [7]", 6, params.getColumnPos(6)); + assertEquals("7 key max 7 L0 adjust", 0, params.mTopRowAdjustment); + assertEquals("7 key max 7 L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [1] [2] [3] [4] [5] [6] [7] ___ ___| + public void testLayout7KeyMax7L1() { + MoreKeysKeyboardParams params = createParams(7, 7, XPOS_L1); + assertEquals("7 key max 7 L1 columns", 7, params.mNumColumns); + assertEquals("7 key max 7 L1 rows", 1, params.mNumRows); + assertEquals("7 key max 7 L1 left", 0, params.mLeftKeys); + assertEquals("7 key max 7 L1 right", 7, params.mRightKeys); + assertEquals("7 key max 7 L1 [1]", 0, params.getColumnPos(0)); + assertEquals("7 key max 7 L1 [2]", 1, params.getColumnPos(1)); + assertEquals("7 key max 7 L1 [3]", 2, params.getColumnPos(2)); + assertEquals("7 key max 7 L1 [4]", 3, params.getColumnPos(3)); + assertEquals("7 key max 7 L1 [5]", 4, params.getColumnPos(4)); + assertEquals("7 key max 7 L1 [6]", 5, params.getColumnPos(5)); + assertEquals("7 key max 7 L1 [7]", 6, params.getColumnPos(6)); + assertEquals("7 key max 7 L1 adjust", 0, params.mTopRowAdjustment); + assertEquals("7 key max 7 L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [3] [1] [2] [4] [5] [6] [7] ___ ___| + public void testLayout7KeyMax7L2() { + MoreKeysKeyboardParams params = createParams(7, 7, XPOS_L2); + assertEquals("7 key max 7 L2 columns", 7, params.mNumColumns); + assertEquals("7 key max 7 L2 rows", 1, params.mNumRows); + assertEquals("7 key max 7 L2 left", 1, params.mLeftKeys); + assertEquals("7 key max 7 L2 right", 6, params.mRightKeys); + assertEquals("7 key max 7 L2 [1]", 0, params.getColumnPos(0)); + assertEquals("7 key max 7 L2 [2]", 1, params.getColumnPos(1)); + assertEquals("7 key max 7 L2 [3]", -1, params.getColumnPos(2)); + assertEquals("7 key max 7 L2 [4]", 2, params.getColumnPos(3)); + assertEquals("7 key max 7 L2 [5]", 3, params.getColumnPos(4)); + assertEquals("7 key max 7 L2 [6]", 4, params.getColumnPos(5)); + assertEquals("7 key max 7 L2 [7]", 5, params.getColumnPos(6)); + assertEquals("7 key max 7 L2 adjust", 0, params.mTopRowAdjustment); + assertEquals("7 key max 7 L2 default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // |___ [5] [3] [1] [2] [4] [6] [7] ___ ___| + public void testLayout7KeyMax7L3() { + MoreKeysKeyboardParams params = createParams(7, 7, XPOS_L3); + assertEquals("7 key max 7 L3 columns", 7, params.mNumColumns); + assertEquals("7 key max 7 L3 rows", 1, params.mNumRows); + assertEquals("7 key max 7 L3 left", 2, params.mLeftKeys); + assertEquals("7 key max 7 L3 right", 5, params.mRightKeys); + assertEquals("7 key max 7 L3 [1]", 0, params.getColumnPos(0)); + assertEquals("7 key max 7 L3 [2]", 1, params.getColumnPos(1)); + assertEquals("7 key max 7 L3 [3]", -1, params.getColumnPos(2)); + assertEquals("7 key max 7 L3 [4]", 2, params.getColumnPos(3)); + assertEquals("7 key max 7 L3 [5]", -2, params.getColumnPos(4)); + assertEquals("7 key max 7 L3 [6]", 3, params.getColumnPos(5)); + assertEquals("7 key max 7 L3 [7]", 4, params.getColumnPos(6)); + assertEquals("7 key max 7 L3 adjust", 0, params.mTopRowAdjustment); + assertEquals("7 key max 7 L3 default", WIDTH * 2, params.getDefaultKeyCoordX()); + } + + // |___ [7] [5] [3] [1] [2] [4] [6] ___ ___| + public void testLayout7KeyMax7M0() { + MoreKeysKeyboardParams params = createParams(7, 7, XPOS_M0); + assertEquals("7 key max 7 M0 columns", 7, params.mNumColumns); + assertEquals("7 key max 7 M0 rows", 1, params.mNumRows); + assertEquals("7 key max 7 M0 left", 3, params.mLeftKeys); + assertEquals("7 key max 7 M0 right", 4, params.mRightKeys); + assertEquals("7 key max 7 M0 [1]", 0, params.getColumnPos(0)); + assertEquals("7 key max 7 M0 [2]", 1, params.getColumnPos(1)); + assertEquals("7 key max 7 M0 [3]", -1, params.getColumnPos(2)); + assertEquals("7 key max 7 M0 [4]", 2, params.getColumnPos(3)); + assertEquals("7 key max 7 M0 [5]", -2, params.getColumnPos(4)); + assertEquals("7 key max 7 M0 [6]", 3, params.getColumnPos(5)); + assertEquals("7 key max 7 M0 [7]", -3, params.getColumnPos(6)); + assertEquals("7 key max 7 M0 adjust", 0, params.mTopRowAdjustment); + assertEquals("7 key max 7 M0 default", WIDTH * 3, params.getDefaultKeyCoordX()); + } + + // |___ ___ [7] [5] [3] [1] [2] [4] [6] ___| + public void testLayout7KeyMax7M1() { + MoreKeysKeyboardParams params = createParams(7, 7, XPOS_M1); + assertEquals("7 key max 7 M1 columns", 7, params.mNumColumns); + assertEquals("7 key max 7 M1 rows", 1, params.mNumRows); + assertEquals("7 key max 7 M1 left", 3, params.mLeftKeys); + assertEquals("7 key max 7 M1 right", 4, params.mRightKeys); + assertEquals("7 key max 7 M1 [1]", 0, params.getColumnPos(0)); + assertEquals("7 key max 7 M1 [2]", 1, params.getColumnPos(1)); + assertEquals("7 key max 7 M1 [3]", -1, params.getColumnPos(2)); + assertEquals("7 key max 7 M1 [4]", 2, params.getColumnPos(3)); + assertEquals("7 key max 7 M1 [5]", -2, params.getColumnPos(4)); + assertEquals("7 key max 7 M1 [6]", 3, params.getColumnPos(5)); + assertEquals("7 key max 7 M1 [7]", -3, params.getColumnPos(6)); + assertEquals("7 key max 7 M1 adjust", 0, params.mTopRowAdjustment); + assertEquals("7 key max 7 M1 default", WIDTH * 3, params.getDefaultKeyCoordX()); + } + + // |___ ___ [7] [6] [5] [3] [1] [2] [4] ___| + public void testLayout7KeyMax7R3() { + MoreKeysKeyboardParams params = createParams(7, 7, XPOS_R3); + assertEquals("7 key max 7 R3 columns", 7, params.mNumColumns); + assertEquals("7 key max 7 R3 rows", 1, params.mNumRows); + assertEquals("7 key max 7 R3 left", 4, params.mLeftKeys); + assertEquals("7 key max 7 R3 right", 3, params.mRightKeys); + assertEquals("7 key max 7 R3 [1]", 0, params.getColumnPos(0)); + assertEquals("7 key max 7 R3 [2]", 1, params.getColumnPos(1)); + assertEquals("7 key max 7 R3 [3]", -1, params.getColumnPos(2)); + assertEquals("7 key max 7 R3 [4]", 2, params.getColumnPos(3)); + assertEquals("7 key max 7 R3 [5]", -2, params.getColumnPos(4)); + assertEquals("7 key max 7 R3 [6]", -3, params.getColumnPos(5)); + assertEquals("7 key max 7 R3 [7]", -4, params.getColumnPos(6)); + assertEquals("7 key max 7 R3 adjust", 0, params.mTopRowAdjustment); + assertEquals("7 key max 7 R3 default", WIDTH * 4, params.getDefaultKeyCoordX()); + } + + // |___ ___ [7] [6] [5] [4] [3] [1] [2] ___| + public void testLayout7KeyMax7R2() { + MoreKeysKeyboardParams params = createParams(7, 7, XPOS_R2); + assertEquals("7 key max 7 R2 columns", 7, params.mNumColumns); + assertEquals("7 key max 7 R2 rows", 1, params.mNumRows); + assertEquals("7 key max 7 R2 left", 5, params.mLeftKeys); + assertEquals("7 key max 7 R2 right", 2, params.mRightKeys); + assertEquals("7 key max 7 R2 [1]", 0, params.getColumnPos(0)); + assertEquals("7 key max 7 R2 [2]", 1, params.getColumnPos(1)); + assertEquals("7 key max 7 R2 [3]", -1, params.getColumnPos(2)); + assertEquals("7 key max 7 R2 [4]", -2, params.getColumnPos(3)); + assertEquals("7 key max 7 R2 [5]", -3, params.getColumnPos(4)); + assertEquals("7 key max 7 R2 [6]", -4, params.getColumnPos(5)); + assertEquals("7 key max 7 R2 [7]", -5, params.getColumnPos(6)); + assertEquals("7 key max 7 R2 adjust", 0, params.mTopRowAdjustment); + assertEquals("7 key max 7 R2 default", WIDTH * 5, params.getDefaultKeyCoordX()); + } + + // |___ ___ [7] [6] [5] [4] [3] [2] [1] ___| + public void testLayout7KeyMax7R1() { + MoreKeysKeyboardParams params = createParams(7, 7, XPOS_R1); + assertEquals("7 key max 7 R1 columns", 7, params.mNumColumns); + assertEquals("7 key max 7 R1 rows", 1, params.mNumRows); + assertEquals("7 key max 7 R1 left", 6, params.mLeftKeys); + assertEquals("7 key max 7 R1 right", 1, params.mRightKeys); + assertEquals("7 key max 7 R1 [1]", 0, params.getColumnPos(0)); + assertEquals("7 key max 7 R1 [2]", -1, params.getColumnPos(1)); + assertEquals("7 key max 7 R1 [3]", -2, params.getColumnPos(2)); + assertEquals("7 key max 7 R1 [4]", -3, params.getColumnPos(3)); + assertEquals("7 key max 7 R1 [5]", -4, params.getColumnPos(4)); + assertEquals("7 key max 7 R1 [6]", -5, params.getColumnPos(5)); + assertEquals("7 key max 7 R1 [7]", -6, params.getColumnPos(6)); + assertEquals("7 key max 7 R1 adjust", 0, params.mTopRowAdjustment); + assertEquals("7 key max 7 R1 default", WIDTH * 6, params.getDefaultKeyCoordX()); + } + + // |___ ___ [7] [6] [5] [4] [3] [2] [1]| + public void testLayout7KeyMax7R0() { + MoreKeysKeyboardParams params = createParams(7, 7, XPOS_R0); + assertEquals("7 key max 7 R0 columns", 7, params.mNumColumns); + assertEquals("7 key max 7 R0 rows", 1, params.mNumRows); + assertEquals("7 key max 7 R0 left", 6, params.mLeftKeys); + assertEquals("7 key max 7 R0 right", 1, params.mRightKeys); + assertEquals("7 key max 7 R0 [1]", 0, params.getColumnPos(0)); + assertEquals("7 key max 7 R0 [2]", -1, params.getColumnPos(1)); + assertEquals("7 key max 7 R0 [3]", -2, params.getColumnPos(2)); + assertEquals("7 key max 7 R0 [4]", -3, params.getColumnPos(3)); + assertEquals("7 key max 7 R0 [5]", -4, params.getColumnPos(4)); + assertEquals("7 key max 7 R0 [6]", -5, params.getColumnPos(5)); + assertEquals("7 key max 7 R0 [7]", -6, params.getColumnPos(6)); + assertEquals("7 key max 7 R0 adjust", 0, params.mTopRowAdjustment); + assertEquals("7 key max 7 R0 default", WIDTH * 6, params.getDefaultKeyCoordX()); + } + + // [7] [5] [6] [8] + // [3] [1] [2] [4] + public void testLayout8KeyMax5M0() { + MoreKeysKeyboardParams params = createParams(8, 5, XPOS_M0); + assertEquals("8 key max 5 M0 columns", 4, params.mNumColumns); + assertEquals("8 key max 5 M0 rows", 2, params.mNumRows); + assertEquals("8 key max 5 M0 left", 1, params.mLeftKeys); + assertEquals("8 key max 5 M0 right", 3, params.mRightKeys); + assertEquals("8 key max 5 M0 [1]", 0, params.getColumnPos(0)); + assertEquals("8 key max 5 M0 [2]", 1, params.getColumnPos(1)); + assertEquals("8 key max 5 M0 [3]", -1, params.getColumnPos(2)); + assertEquals("8 key max 5 M0 [4]", 2, params.getColumnPos(3)); + assertEquals("8 key max 5 M0 [5]", 0, params.getColumnPos(4)); + assertEquals("8 key max 5 M0 [6]", 1, params.getColumnPos(5)); + assertEquals("8 key max 5 M0 [7]", -1, params.getColumnPos(6)); + assertEquals("8 key max 5 M0 [8]", 2, params.getColumnPos(7)); + assertEquals("8 key max 5 M0 adjust", 0, params.mTopRowAdjustment); + assertEquals("8 key max 5 M0 default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // |[5] [6] [7] [8] + // |[1] [2] [3] [4] + public void testLayout8KeyMax5L0() { + MoreKeysKeyboardParams params = createParams(8, 5, XPOS_L0); + assertEquals("8 key max 5 L0 columns", 4, params.mNumColumns); + assertEquals("8 key max 5 L0 rows", 2, params.mNumRows); + assertEquals("8 key max 5 L0 left", 0, params.mLeftKeys); + assertEquals("8 key max 5 L0 right", 4, params.mRightKeys); + assertEquals("8 key max 5 L0 [1]", 0, params.getColumnPos(0)); + assertEquals("8 key max 5 L0 [2]", 1, params.getColumnPos(1)); + assertEquals("8 key max 5 L0 [3]", 2, params.getColumnPos(2)); + assertEquals("8 key max 5 L0 [4]", 3, params.getColumnPos(3)); + assertEquals("8 key max 5 L0 [5]", 0, params.getColumnPos(4)); + assertEquals("8 key max 5 L0 [6]", 1, params.getColumnPos(5)); + assertEquals("8 key max 5 L0 [7]", 2, params.getColumnPos(6)); + assertEquals("8 key max 5 L0 [8]", 3, params.getColumnPos(7)); + assertEquals("8 key max 5 L0 adjust", 0, params.mTopRowAdjustment); + assertEquals("8 key max 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [5] [6] [7] [8] + // |___ [1] [2] [3] [4] + public void testLayout8KeyMax5L1() { + MoreKeysKeyboardParams params = createParams(8, 5, XPOS_L1); + assertEquals("8 key max 5 L1 columns", 4, params.mNumColumns); + assertEquals("8 key max 5 L1 rows", 2, params.mNumRows); + assertEquals("8 key max 5 L1 left", 0, params.mLeftKeys); + assertEquals("8 key max 5 L1 right", 4, params.mRightKeys); + assertEquals("8 key max 5 L1 [1]", 0, params.getColumnPos(0)); + assertEquals("8 key max 5 L1 [2]", 1, params.getColumnPos(1)); + assertEquals("8 key max 5 L1 [3]", 2, params.getColumnPos(2)); + assertEquals("8 key max 5 L1 [4]", 3, params.getColumnPos(3)); + assertEquals("8 key max 5 L1 [5]", 0, params.getColumnPos(4)); + assertEquals("8 key max 5 L1 [6]", 1, params.getColumnPos(5)); + assertEquals("8 key max 5 L1 [7]", 2, params.getColumnPos(6)); + assertEquals("8 key max 5 L1 [8]", 3, params.getColumnPos(7)); + assertEquals("8 key max 5 L1 adjust", 0, params.mTopRowAdjustment); + assertEquals("8 key max 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [7] [5] [6] [8] + // |___ [3] [1] [2] [4] + public void testLayout8KeyMax5L2() { + MoreKeysKeyboardParams params = createParams(8, 5, XPOS_L2); + assertEquals("8 key max 5 L2 columns", 4, params.mNumColumns); + assertEquals("8 key max 5 L2 rows", 2, params.mNumRows); + assertEquals("8 key max 5 L2 left", 1, params.mLeftKeys); + assertEquals("8 key max 5 L2 right", 3, params.mRightKeys); + assertEquals("8 key max 5 L2 [1]", 0, params.getColumnPos(0)); + assertEquals("8 key max 5 L2 [2]", 1, params.getColumnPos(1)); + assertEquals("8 key max 5 L2 [3]", -1, params.getColumnPos(2)); + assertEquals("8 key max 5 L2 [4]", 2, params.getColumnPos(3)); + assertEquals("8 key max 5 L2 [5]", 0, params.getColumnPos(4)); + assertEquals("8 key max 5 L2 [6]", 1, params.getColumnPos(5)); + assertEquals("8 key max 5 L2 [7]", -1, params.getColumnPos(6)); + assertEquals("8 key max 5 L2 [8]", 2, params.getColumnPos(7)); + assertEquals("8 key max 5 L2 adjust", 0, params.mTopRowAdjustment); + assertEquals("8 key max 5 L2 default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // [8] [7] [6] [5]| + // [4] [3] [2] [1]| + public void testLayout8KeyMax5R0() { + MoreKeysKeyboardParams params = createParams(8, 5, XPOS_R0); + assertEquals("8 key max 5 R0 columns", 4, params.mNumColumns); + assertEquals("8 key max 5 R0 rows", 2, params.mNumRows); + assertEquals("8 key max 5 R0 left", 3, params.mLeftKeys); + assertEquals("8 key max 5 R0 right", 1, params.mRightKeys); + assertEquals("8 key max 5 R0 [1]", 0, params.getColumnPos(0)); + assertEquals("8 key max 5 R0 [2]", -1, params.getColumnPos(1)); + assertEquals("8 key max 5 R0 [3]", -2, params.getColumnPos(2)); + assertEquals("8 key max 5 R0 [4]", -3, params.getColumnPos(3)); + assertEquals("8 key max 5 R0 [5]", 0, params.getColumnPos(4)); + assertEquals("8 key max 5 R0 [6]", -1, params.getColumnPos(5)); + assertEquals("8 key max 5 R0 [7]", -2, params.getColumnPos(6)); + assertEquals("8 key max 5 R0 [8]", -3, params.getColumnPos(7)); + assertEquals("8 key max 5 R0 adjust", 0, params.mTopRowAdjustment); + assertEquals("8 key max 5 R0 default", WIDTH * 3, params.getDefaultKeyCoordX()); + } + + // [8] [7] [6] [5] ___| + // [4] [3] [2] [1] ___| + public void testLayout8KeyMax5R1() { + MoreKeysKeyboardParams params = createParams(8, 5, XPOS_R1); + assertEquals("8 key max 5 R1 columns", 4, params.mNumColumns); + assertEquals("8 key max 5 R1 rows", 2, params.mNumRows); + assertEquals("8 key max 5 R1 left", 3, params.mLeftKeys); + assertEquals("8 key max 5 R1 right", 1, params.mRightKeys); + assertEquals("8 key max 5 R1 [1]", 0, params.getColumnPos(0)); + assertEquals("8 key max 5 R1 [2]", -1, params.getColumnPos(1)); + assertEquals("8 key max 5 R1 [3]", -2, params.getColumnPos(2)); + assertEquals("8 key max 5 R1 [4]", -3, params.getColumnPos(3)); + assertEquals("8 key max 5 R1 [5]", 0, params.getColumnPos(4)); + assertEquals("8 key max 5 R1 [6]", -1, params.getColumnPos(5)); + assertEquals("8 key max 5 R1 [7]", -2, params.getColumnPos(6)); + assertEquals("8 key max 5 R1 [8]", -3, params.getColumnPos(7)); + assertEquals("8 key max 5 R1 adjust", 0, params.mTopRowAdjustment); + assertEquals("8 key max 5 R1 default", WIDTH * 3, params.getDefaultKeyCoordX()); + } + + // [8] [7] [5] [6] ___| + // [4] [3] [1] [2] ___| + public void testLayout8KeyMax5R2() { + MoreKeysKeyboardParams params = createParams(8, 5, XPOS_R2); + assertEquals("8 key max 5 R2 columns", 4, params.mNumColumns); + assertEquals("8 key max 5 R2 rows", 2, params.mNumRows); + assertEquals("8 key max 5 R2 left", 2, params.mLeftKeys); + assertEquals("8 key max 5 R2 right", 2, params.mRightKeys); + assertEquals("8 key max 5 R2 [1]", 0, params.getColumnPos(0)); + assertEquals("8 key max 5 R2 [2]", 1, params.getColumnPos(1)); + assertEquals("8 key max 5 R2 [3]", -1, params.getColumnPos(2)); + assertEquals("8 key max 5 R2 [4]", -2, params.getColumnPos(3)); + assertEquals("8 key max 5 R2 [5]", 0, params.getColumnPos(4)); + assertEquals("8 key max 5 R2 [6]", 1, params.getColumnPos(5)); + assertEquals("8 key max 5 R2 [7]", -1, params.getColumnPos(6)); + assertEquals("8 key max 5 R2 [8]", -2, params.getColumnPos(7)); + assertEquals("8 key max 5 R2 adjust", 0, params.mTopRowAdjustment); + assertEquals("8 key max 5 R2 default", WIDTH * 2, params.getDefaultKeyCoordX()); + } + + // [8] [6] [7] [9] + // [5] [3] [1] [2] [4] + public void testLayout9KeyMax5M0() { + MoreKeysKeyboardParams params = createParams(9, 5, XPOS_M0); + assertEquals("9 key max 5 M0 columns", 5, params.mNumColumns); + assertEquals("9 key max 5 M0 rows", 2, params.mNumRows); + assertEquals("9 key max 5 M0 left", 2, params.mLeftKeys); + assertEquals("9 key max 5 M0 right", 3, params.mRightKeys); + assertEquals("9 key max 5 M0 [1]", 0, params.getColumnPos(0)); + assertEquals("9 key max 5 M0 [2]", 1, params.getColumnPos(1)); + assertEquals("9 key max 5 M0 [3]", -1, params.getColumnPos(2)); + assertEquals("9 key max 5 M0 [4]", 2, params.getColumnPos(3)); + assertEquals("9 key max 5 M0 [5]", -2, params.getColumnPos(4)); + assertEquals("9 key max 5 M0 [6]", 0, params.getColumnPos(5)); + assertEquals("9 key max 5 M0 [7]", 1, params.getColumnPos(6)); + assertEquals("9 key max 5 M0 [8]", -1, params.getColumnPos(7)); + assertEquals("9 key max 5 M0 [9]", 2, params.getColumnPos(8)); + assertEquals("9 key max 5 M0 adjust", -1, params.mTopRowAdjustment); + assertEquals("9 key max 5 M0 default", WIDTH * 2, params.getDefaultKeyCoordX()); + } + + // | [6] [7] [8] [9] + // |[1] [2] [3] [4] [5] + public void testLayout9KeyMax5L0() { + MoreKeysKeyboardParams params = createParams(9, 5, XPOS_L0); + assertEquals("9 key max 5 L0 columns", 5, params.mNumColumns); + assertEquals("9 key max 5 L0 rows", 2, params.mNumRows); + assertEquals("9 key max 5 L0 left", 0, params.mLeftKeys); + assertEquals("9 key max 5 L0 right", 5, params.mRightKeys); + assertEquals("9 key max 5 L0 [1]", 0, params.getColumnPos(0)); + assertEquals("9 key max 5 L0 [2]", 1, params.getColumnPos(1)); + assertEquals("9 key max 5 L0 [3]", 2, params.getColumnPos(2)); + assertEquals("9 key max 5 L0 [4]", 3, params.getColumnPos(3)); + assertEquals("9 key max 5 L0 [5]", 4, params.getColumnPos(4)); + assertEquals("9 key max 5 L0 [6]", 0, params.getColumnPos(5)); + assertEquals("9 key max 5 L0 [7]", 1, params.getColumnPos(6)); + assertEquals("9 key max 5 L0 [8]", 2, params.getColumnPos(7)); + assertEquals("9 key max 5 L0 [9]", 3, params.getColumnPos(8)); + assertEquals("9 key max 5 L0 adjust", 1, params.mTopRowAdjustment); + assertEquals("9 key max 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [6] [7] [8] [9] + // |___ [1] [2] [3] [4] [5] + public void testLayout9KeyMax5L1() { + MoreKeysKeyboardParams params = createParams(9, 5, XPOS_L1); + assertEquals("9 key max 5 L1 columns", 5, params.mNumColumns); + assertEquals("9 key max 5 L1 rows", 2, params.mNumRows); + assertEquals("9 key max 5 L1 left", 0, params.mLeftKeys); + assertEquals("9 key max 5 L1 right", 5, params.mRightKeys); + assertEquals("9 key max 5 L1 [1]", 0, params.getColumnPos(0)); + assertEquals("9 key max 5 L1 [2]", 1, params.getColumnPos(1)); + assertEquals("9 key max 5 L1 [3]", 2, params.getColumnPos(2)); + assertEquals("9 key max 5 L1 [4]", 3, params.getColumnPos(3)); + assertEquals("9 key max 5 L1 [5]", 4, params.getColumnPos(4)); + assertEquals("9 key max 5 L1 [6]", 0, params.getColumnPos(5)); + assertEquals("9 key max 5 L1 [7]", 1, params.getColumnPos(6)); + assertEquals("9 key max 5 L1 [8]", 2, params.getColumnPos(7)); + assertEquals("9 key max 5 L1 [9]", 3, params.getColumnPos(8)); + assertEquals("9 key max 5 L1 adjust",1, params.mTopRowAdjustment); + assertEquals("9 key max 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [8] [6] [7] [9] + // |___ [3] [1] [2] [4] [5] + public void testLayout9KeyMax5L2() { + MoreKeysKeyboardParams params = createParams(9, 5, XPOS_L2); + assertEquals("9 key max 5 L2 columns", 5, params.mNumColumns); + assertEquals("9 key max 5 L2 rows", 2, params.mNumRows); + assertEquals("9 key max 5 L2 left", 1, params.mLeftKeys); + assertEquals("9 key max 5 L2 right", 4, params.mRightKeys); + assertEquals("9 key max 5 L2 [1]", 0, params.getColumnPos(0)); + assertEquals("9 key max 5 L2 [2]", 1, params.getColumnPos(1)); + assertEquals("9 key max 5 L2 [3]", -1, params.getColumnPos(2)); + assertEquals("9 key max 5 L2 [4]", 2, params.getColumnPos(3)); + assertEquals("9 key max 5 L2 [5]", 3, params.getColumnPos(4)); + assertEquals("9 key max 5 L2 [6]", 0, params.getColumnPos(5)); + assertEquals("9 key max 5 L2 [7]", 1, params.getColumnPos(6)); + assertEquals("9 key max 5 L2 [8]", -1, params.getColumnPos(7)); + assertEquals("9 key max 5 L2 [9]", 2, params.getColumnPos(8)); + assertEquals("9 key max 5 L2 adjust", 1, params.mTopRowAdjustment); + assertEquals("9 key max 5 L2 default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // [9] [8] [7] [6] | + // [5] [4] [3] [2] [1]| + public void testLayout9KeyMax5R0() { + MoreKeysKeyboardParams params = createParams(9, 5, XPOS_R0); + assertEquals("9 key max 5 R0 columns", 5, params.mNumColumns); + assertEquals("9 key max 5 R0 rows", 2, params.mNumRows); + assertEquals("9 key max 5 R0 left", 4, params.mLeftKeys); + assertEquals("9 key max 5 R0 right", 1, params.mRightKeys); + assertEquals("9 key max 5 R0 [1]", 0, params.getColumnPos(0)); + assertEquals("9 key max 5 R0 [2]", -1, params.getColumnPos(1)); + assertEquals("9 key max 5 R0 [3]", -2, params.getColumnPos(2)); + assertEquals("9 key max 5 R0 [4]", -3, params.getColumnPos(3)); + assertEquals("9 key max 5 R0 [5]", -4, params.getColumnPos(4)); + assertEquals("9 key max 5 R0 [6]", 0, params.getColumnPos(5)); + assertEquals("9 key max 5 R0 [7]", -1, params.getColumnPos(6)); + assertEquals("9 key max 5 R0 [8]", -2, params.getColumnPos(7)); + assertEquals("9 key max 5 R0 [9]", -3, params.getColumnPos(8)); + assertEquals("9 key max 5 R0 adjust", -1, params.mTopRowAdjustment); + assertEquals("9 key max 5 R0 default", WIDTH * 4, params.getDefaultKeyCoordX()); + } + + // [9] [8] [7] [6] ___| + // [5] [4] [3] [2] [1] ___| + public void testLayout9KeyMax5R1() { + MoreKeysKeyboardParams params = createParams(9, 5, XPOS_R1); + assertEquals("9 key max 5 R1 columns", 5, params.mNumColumns); + assertEquals("9 key max 5 R1 rows", 2, params.mNumRows); + assertEquals("9 key max 5 R1 left", 4, params.mLeftKeys); + assertEquals("9 key max 5 R1 right", 1, params.mRightKeys); + assertEquals("9 key max 5 R1 [1]", 0, params.getColumnPos(0)); + assertEquals("9 key max 5 R1 [2]", -1, params.getColumnPos(1)); + assertEquals("9 key max 5 R1 [3]", -2, params.getColumnPos(2)); + assertEquals("9 key max 5 R1 [4]", -3, params.getColumnPos(3)); + assertEquals("9 key max 5 R1 [5]", -4, params.getColumnPos(4)); + assertEquals("9 key max 5 R1 [6]", 0, params.getColumnPos(5)); + assertEquals("9 key max 5 R1 [7]", -1, params.getColumnPos(6)); + assertEquals("9 key max 5 R1 [8]", -2, params.getColumnPos(7)); + assertEquals("9 key max 5 R1 [9]", -3, params.getColumnPos(8)); + assertEquals("9 key max 5 R1 adjust", -1, params.mTopRowAdjustment); + assertEquals("9 key max 5 R1 default", WIDTH * 4, params.getDefaultKeyCoordX()); + } + + // [9] [8] [6] [7] ___| + // [5] [4] [3] [1] [2] ___| + public void testLayout9KeyMax5R2() { + MoreKeysKeyboardParams params = createParams(9, 5, XPOS_R2); + assertEquals("9 key max 5 R2 columns", 5, params.mNumColumns); + assertEquals("9 key max 5 R2 rows", 2, params.mNumRows); + assertEquals("9 key max 5 R2 left", 3, params.mLeftKeys); + assertEquals("9 key max 5 R2 right", 2, params.mRightKeys); + assertEquals("9 key max 5 R2 [1]", 0, params.getColumnPos(0)); + assertEquals("9 key max 5 R2 [2]", 1, params.getColumnPos(1)); + assertEquals("9 key max 5 R2 [3]", -1, params.getColumnPos(2)); + assertEquals("9 key max 5 R2 [4]", -2, params.getColumnPos(3)); + assertEquals("9 key max 5 R2 [5]", -3, params.getColumnPos(4)); + assertEquals("9 key max 5 R2 [6]", 0, params.getColumnPos(5)); + assertEquals("9 key max 5 R2 [7]", 1, params.getColumnPos(6)); + assertEquals("9 key max 5 R2 [8]", -1, params.getColumnPos(7)); + assertEquals("9 key max 5 R2 [9]", -2, params.getColumnPos(8)); + assertEquals("9 key max 5 R2 adjust", -1, params.mTopRowAdjustment); + assertEquals("9 key max 5 R2 default", WIDTH * 3, params.getDefaultKeyCoordX()); + } + + // [A] [8] [6] [7] [9] + // [5] [3] [1] [2] [4] + public void testLayout10KeyMax5M0() { + MoreKeysKeyboardParams params = createParams(10, 5, XPOS_M0); + assertEquals("10 key max 5 M0 columns", 5, params.mNumColumns); + assertEquals("10 key max 5 M0 rows", 2, params.mNumRows); + assertEquals("10 key max 5 M0 left", 2, params.mLeftKeys); + assertEquals("10 key max 5 M0 right", 3, params.mRightKeys); + assertEquals("10 key max 5 M0 [1]", 0, params.getColumnPos(0)); + assertEquals("10 key max 5 M0 [2]", 1, params.getColumnPos(1)); + assertEquals("10 key max 5 M0 [3]", -1, params.getColumnPos(2)); + assertEquals("10 key max 5 M0 [4]", 2, params.getColumnPos(3)); + assertEquals("10 key max 5 M0 [5]", -2, params.getColumnPos(4)); + assertEquals("10 key max 5 M0 [6]", 0, params.getColumnPos(5)); + assertEquals("10 key max 5 M0 [7]", 1, params.getColumnPos(6)); + assertEquals("10 key max 5 M0 [8]", -1, params.getColumnPos(7)); + assertEquals("10 key max 5 M0 [9]", 2, params.getColumnPos(8)); + assertEquals("10 key max 5 M0 [A]", -2, params.getColumnPos(9)); + assertEquals("10 key max 5 M0 adjust", 0, params.mTopRowAdjustment); + assertEquals("10 key max 5 M0 default", WIDTH * 2, params.getDefaultKeyCoordX()); + } + + // |[6] [7] [8] [9] [A] + // |[1] [2] [3] [4] [5] + public void testLayout10KeyMax5L0() { + MoreKeysKeyboardParams params = createParams(10, 5, XPOS_L0); + assertEquals("10 key max 5 L0 columns", 5, params.mNumColumns); + assertEquals("10 key max 5 L0 rows", 2, params.mNumRows); + assertEquals("10 key max 5 L0 left", 0, params.mLeftKeys); + assertEquals("10 key max 5 L0 right", 5, params.mRightKeys); + assertEquals("10 key max 5 L0 [1]", 0, params.getColumnPos(0)); + assertEquals("10 key max 5 L0 [2]", 1, params.getColumnPos(1)); + assertEquals("10 key max 5 L0 [3]", 2, params.getColumnPos(2)); + assertEquals("10 key max 5 L0 [4]", 3, params.getColumnPos(3)); + assertEquals("10 key max 5 L0 [5]", 4, params.getColumnPos(4)); + assertEquals("10 key max 5 L0 [6]", 0, params.getColumnPos(5)); + assertEquals("10 key max 5 L0 [7]", 1, params.getColumnPos(6)); + assertEquals("10 key max 5 L0 [8]", 2, params.getColumnPos(7)); + assertEquals("10 key max 5 L0 [9]", 3, params.getColumnPos(8)); + assertEquals("10 key max 5 L0 [A]", 4, params.getColumnPos(9)); + assertEquals("10 key max 5 L0 adjust", 0, params.mTopRowAdjustment); + assertEquals("10 key max 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [6] [7] [8] [9] [A] + // |___ [1] [2] [3] [4] [5] + public void testLayout10KeyMax5L1() { + MoreKeysKeyboardParams params = createParams(10, 5, XPOS_L1); + assertEquals("10 key max 5 L1 columns", 5, params.mNumColumns); + assertEquals("10 key max 5 L1 rows", 2, params.mNumRows); + assertEquals("10 key max 5 L1 left", 0, params.mLeftKeys); + assertEquals("10 key max 5 L1 right", 5, params.mRightKeys); + assertEquals("10 key max 5 L1 [1]", 0, params.getColumnPos(0)); + assertEquals("10 key max 5 L1 [2]", 1, params.getColumnPos(1)); + assertEquals("10 key max 5 L1 [3]", 2, params.getColumnPos(2)); + assertEquals("10 key max 5 L1 [4]", 3, params.getColumnPos(3)); + assertEquals("10 key max 5 L1 [5]", 4, params.getColumnPos(4)); + assertEquals("10 key max 5 L1 [6]", 0, params.getColumnPos(5)); + assertEquals("10 key max 5 L1 [7]", 1, params.getColumnPos(6)); + assertEquals("10 key max 5 L1 [8]", 2, params.getColumnPos(7)); + assertEquals("10 key max 5 L1 [9]", 3, params.getColumnPos(8)); + assertEquals("10 key max 5 L1 [A]", 4, params.getColumnPos(9)); + assertEquals("10 key max 5 L1 adjust", 0, params.mTopRowAdjustment); + assertEquals("10 key max 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX()); + } + + // |___ [8] [6] [7] [9] [A] + // |___ [3] [1] [2] [4] [5] + public void testLayout10KeyMax5L2() { + MoreKeysKeyboardParams params = createParams(10, 5, XPOS_L2); + assertEquals("10 key max 5 L2 columns", 5, params.mNumColumns); + assertEquals("10 key max 5 L2 rows", 2, params.mNumRows); + assertEquals("10 key max 5 L2 left", 1, params.mLeftKeys); + assertEquals("10 key max 5 L2 right", 4, params.mRightKeys); + assertEquals("10 key max 5 L2 [1]", 0, params.getColumnPos(0)); + assertEquals("10 key max 5 L2 [2]", 1, params.getColumnPos(1)); + assertEquals("10 key max 5 L2 [3]", -1, params.getColumnPos(2)); + assertEquals("10 key max 5 L2 [4]", 2, params.getColumnPos(3)); + assertEquals("10 key max 5 L2 [5]", 3, params.getColumnPos(4)); + assertEquals("10 key max 5 L2 [6]", 0, params.getColumnPos(5)); + assertEquals("10 key max 5 L2 [7]", 1, params.getColumnPos(6)); + assertEquals("10 key max 5 L2 [8]", -1, params.getColumnPos(7)); + assertEquals("10 key max 5 L2 [9]", 2, params.getColumnPos(8)); + assertEquals("10 key max 5 L2 [A]", 3, params.getColumnPos(9)); + assertEquals("10 key max 5 L2 adjust", 0, params.mTopRowAdjustment); + assertEquals("10 key max 5 L2 default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // [A] [9] [8] [7] [6]| + // [5] [4] [3] [2] [1]| + public void testLayout10KeyMax5R0() { + MoreKeysKeyboardParams params = createParams(10, 5, XPOS_R0); + assertEquals("10 key max 5 R0 columns", 5, params.mNumColumns); + assertEquals("10 key max 5 R0 rows", 2, params.mNumRows); + assertEquals("10 key max 5 R0 left", 4, params.mLeftKeys); + assertEquals("10 key max 5 R0 right", 1, params.mRightKeys); + assertEquals("10 key max 5 R0 [1]", 0, params.getColumnPos(0)); + assertEquals("10 key max 5 R0 [2]", -1, params.getColumnPos(1)); + assertEquals("10 key max 5 R0 [3]", -2, params.getColumnPos(2)); + assertEquals("10 key max 5 R0 [4]", -3, params.getColumnPos(3)); + assertEquals("10 key max 5 R0 [5]", -4, params.getColumnPos(4)); + assertEquals("10 key max 5 R0 [6]", 0, params.getColumnPos(5)); + assertEquals("10 key max 5 R0 [7]", -1, params.getColumnPos(6)); + assertEquals("10 key max 5 R0 [8]", -2, params.getColumnPos(7)); + assertEquals("10 key max 5 R0 [9]", -3, params.getColumnPos(8)); + assertEquals("10 key max 5 R0 [A]", -4, params.getColumnPos(9)); + assertEquals("10 key max 5 R0 adjust", 0, params.mTopRowAdjustment); + assertEquals("10 key max 5 R0 default", WIDTH * 4, params.getDefaultKeyCoordX()); + } + + // [A] [9] [8] [7] [6] ___| + // [5] [4] [3] [2] [1] ___| + public void testLayout10KeyMax5R1() { + MoreKeysKeyboardParams params = createParams(10, 5, XPOS_R1); + assertEquals("10 key max 5 R1 columns", 5, params.mNumColumns); + assertEquals("10 key max 5 R1 rows", 2, params.mNumRows); + assertEquals("10 key max 5 R1 left", 4, params.mLeftKeys); + assertEquals("10 key max 5 R1 right", 1, params.mRightKeys); + assertEquals("10 key max 5 R1 [1]", 0, params.getColumnPos(0)); + assertEquals("10 key max 5 R1 [2]", -1, params.getColumnPos(1)); + assertEquals("10 key max 5 R1 [3]", -2, params.getColumnPos(2)); + assertEquals("10 key max 5 R1 [4]", -3, params.getColumnPos(3)); + assertEquals("10 key max 5 R1 [5]", -4, params.getColumnPos(4)); + assertEquals("10 key max 5 R1 [6]", 0, params.getColumnPos(5)); + assertEquals("10 key max 5 R1 [7]", -1, params.getColumnPos(6)); + assertEquals("10 key max 5 R1 [8]", -2, params.getColumnPos(7)); + assertEquals("10 key max 5 R1 [9]", -3, params.getColumnPos(8)); + assertEquals("10 key max 5 R1 [A]", -4, params.getColumnPos(9)); + assertEquals("10 key max 5 R1 adjust", 0, params.mTopRowAdjustment); + assertEquals("10 key max 5 R1 default", WIDTH * 4, params.getDefaultKeyCoordX()); + } + + // [A] [9] [8] [6] [7] ___| + // [5] [4] [3] [1] [2] ___| + public void testLayout10KeyMax5R2() { + MoreKeysKeyboardParams params = createParams(10, 5, XPOS_R2); + assertEquals("10 key max 5 R2 columns", 5, params.mNumColumns); + assertEquals("10 key max 5 R2 rows", 2, params.mNumRows); + assertEquals("10 key max 5 R2 left", 3, params.mLeftKeys); + assertEquals("10 key max 5 R2 right", 2, params.mRightKeys); + assertEquals("10 key max 5 R2 [1]", 0, params.getColumnPos(0)); + assertEquals("10 key max 5 R2 [2]", 1, params.getColumnPos(1)); + assertEquals("10 key max 5 R2 [3]", -1, params.getColumnPos(2)); + assertEquals("10 key max 5 R2 [4]", -2, params.getColumnPos(3)); + assertEquals("10 key max 5 R2 [5]", -3, params.getColumnPos(4)); + assertEquals("10 key max 5 R2 [6]", 0, params.getColumnPos(5)); + assertEquals("10 key max 5 R2 [7]", 1, params.getColumnPos(6)); + assertEquals("10 key max 5 R2 [8]", -1, params.getColumnPos(7)); + assertEquals("10 key max 5 R2 [9]", -2, params.getColumnPos(8)); + assertEquals("10 key max 5 R2 [A]", -3, params.getColumnPos(9)); + assertEquals("10 key max 5 R2 adjust", 0, params.mTopRowAdjustment); + assertEquals("10 key max 5 R2 default", WIDTH * 3, params.getDefaultKeyCoordX()); + } + + // [B] [9] [A] + // [7] [5] [6] [8] + // [3] [1] [2] [4] + public void testLayout11KeyMax5M0() { + MoreKeysKeyboardParams params = createParams(11, 5, XPOS_M0); + assertEquals("11 key max 5 M0 columns", 4, params.mNumColumns); + assertEquals("11 key max 5 M0 rows", 3, params.mNumRows); + assertEquals("11 key max 5 M0 left", 1, params.mLeftKeys); + assertEquals("11 key max 5 M0 right", 3, params.mRightKeys); + assertEquals("11 key max 5 M0 [1]", 0, params.getColumnPos(0)); + assertEquals("11 key max 5 M0 [2]", 1, params.getColumnPos(1)); + assertEquals("11 key max 5 M0 [3]", -1, params.getColumnPos(2)); + assertEquals("11 key max 5 M0 [4]", 2, params.getColumnPos(3)); + assertEquals("11 key max 5 M0 [5]", 0, params.getColumnPos(4)); + assertEquals("11 key max 5 M0 [6]", 1, params.getColumnPos(5)); + assertEquals("11 key max 5 M0 [7]", -1, params.getColumnPos(6)); + assertEquals("11 key max 5 M0 [8]", 2, params.getColumnPos(7)); + assertEquals("11 key max 5 M0 [9]", 0, params.getColumnPos(8)); + assertEquals("11 key max 5 M0 [A]", 1, params.getColumnPos(9)); + assertEquals("11 key max 5 M0 [B]", -1, params.getColumnPos(10)); + assertEquals("11 key max 5 M0 adjust", 1, params.mTopRowAdjustment); + assertEquals("11 key max 5 M0 default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + // [B] [9] [A] [C] + // [7] [5] [6] [8] + // [3] [1] [2] [4] + public void testLayout12KeyMax5M0() { + MoreKeysKeyboardParams params = createParams(12, 5, XPOS_M0); + assertEquals("12 key max 5 M0 columns", 4, params.mNumColumns); + assertEquals("12 key max 5 M0 rows", 3, params.mNumRows); + assertEquals("12 key max 5 M0 left", 1, params.mLeftKeys); + assertEquals("12 key max 5 M0 right", 3, params.mRightKeys); + assertEquals("12 key max 5 M0 [1]", 0, params.getColumnPos(0)); + assertEquals("12 key max 5 M0 [2]", 1, params.getColumnPos(1)); + assertEquals("12 key max 5 M0 [3]", -1, params.getColumnPos(2)); + assertEquals("12 key max 5 M0 [4]", 2, params.getColumnPos(3)); + assertEquals("12 key max 5 M0 [5]", 0, params.getColumnPos(4)); + assertEquals("12 key max 5 M0 [6]", 1, params.getColumnPos(5)); + assertEquals("12 key max 5 M0 [7]", -1, params.getColumnPos(6)); + assertEquals("12 key max 5 M0 [8]", 2, params.getColumnPos(7)); + assertEquals("12 key max 5 M0 [9]", 0, params.getColumnPos(8)); + assertEquals("12 key max 5 M0 [A]", 1, params.getColumnPos(9)); + assertEquals("12 key max 5 M0 [B]", -1, params.getColumnPos(10)); + assertEquals("12 key max 5 M0 [C]", 2, params.getColumnPos(11)); + assertEquals("12 key max 5 M0 adjust", 0, params.mTopRowAdjustment); + assertEquals("12 key max 5 M0 default", WIDTH * 1, params.getDefaultKeyCoordX()); + } + + + // [D] [B] [C] + // [A] [8] [6] [7] [9] + // [5] [3] [1] [2] [4] + public void testLayout13KeyMax5M0() { + MoreKeysKeyboardParams params = createParams(13, 5, XPOS_M0); + assertEquals("13 key max 5 M0 columns", 5, params.mNumColumns); + assertEquals("13 key max 5 M0 rows", 3, params.mNumRows); + assertEquals("13 key max 5 M0 left", 2, params.mLeftKeys); + assertEquals("13 key max 5 M0 right", 3, params.mRightKeys); + assertEquals("13 key max 5 M0 [1]", 0, params.getColumnPos(0)); + assertEquals("13 key max 5 M0 [2]", 1, params.getColumnPos(1)); + assertEquals("13 key max 5 M0 [3]", -1, params.getColumnPos(2)); + assertEquals("13 key max 5 M0 [4]", 2, params.getColumnPos(3)); + assertEquals("13 key max 5 M0 [5]", -2, params.getColumnPos(4)); + assertEquals("13 key max 5 M0 [6]", 0, params.getColumnPos(5)); + assertEquals("13 key max 5 M0 [7]", 1, params.getColumnPos(6)); + assertEquals("13 key max 5 M0 [8]", -1, params.getColumnPos(7)); + assertEquals("13 key max 5 M0 [9]", 2, params.getColumnPos(8)); + assertEquals("13 key max 5 M0 [A]", -2, params.getColumnPos(9)); + assertEquals("13 key max 5 M0 [B]", 0, params.getColumnPos(10)); + assertEquals("13 key max 5 M0 [C]", 1, params.getColumnPos(11)); + assertEquals("13 key max 5 M0 [D]", -1, params.getColumnPos(12)); + assertEquals("13 key max 5 M0 adjust", 0, params.mTopRowAdjustment); + assertEquals("13 key max 5 M0 default", WIDTH * 2, params.getDefaultKeyCoordX()); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java new file mode 100644 index 000000000..e090031e4 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.keyboard.internal; + +import android.content.res.Resources; +import android.test.AndroidTestCase; +import android.text.TextUtils; + +import com.android.inputmethod.latin.tests.R; + +import java.util.Arrays; + +public class KeySpecParserCsvTests extends AndroidTestCase { + private Resources mTestResources; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mTestResources = getTestContext().getResources(); + } + + private static String format(String message, Object expected, Object actual) { + return message + " expected:<" + expected + "> but was:<" + actual + ">"; + } + + private void assertTextArray(String message, String value, String ... expected) { + final String actual[] = KeySpecParser.parseCsvString(value, mTestResources, + R.string.empty_string); + if (expected.length == 0) { + assertNull(message + ": expected=null actual=" + Arrays.toString(actual), + actual); + return; + } + assertEquals(message + ": expected=" + Arrays.toString(expected) + + " actual=" + Arrays.toString(actual) + + ": result length", expected.length, actual.length); + for (int i = 0; i < actual.length; i++) { + final boolean equals = TextUtils.equals(expected[i], actual[i]); + assertTrue(format(message + ": result at " + i + ":", expected[i], actual[i]), equals); + } + } + + private void assertError(String message, String value, String ... expected) { + try { + assertTextArray(message, value, expected); + fail(message); + } catch (Exception pcpe) { + // success. + } + } + + // \U001d11e: MUSICAL SYMBOL G CLEF + private static final String PAIR1 = "\ud834\udd1e"; + // \U001d122: MUSICAL SYMBOL F CLEF + private static final String PAIR2 = "\ud834\udd22"; + // \U002f8a6: CJK COMPATIBILITY IDEOGRAPH-2F8A6; variant character of \u6148. + private static final String PAIR3 = "\ud87e\udca6"; + private static final String SURROGATE1 = PAIR1 + PAIR2; + private static final String SURROGATE2 = PAIR1 + PAIR2 + PAIR3; + + public void testParseCsvTextZero() { + assertTextArray("Empty string", ""); + assertTextArray("Empty entry", ","); + assertTextArray("Empty entry at beginning", ",a", "a"); + assertTextArray("Empty entry at end", "a,", "a"); + assertTextArray("Empty entry at middle", "a,,b", "a", "b"); + assertTextArray("Empty entries with escape", ",a,b\\,c,,d,", "a", "b\\,c", "d"); + } + + public void testParseCsvTextSingle() { + assertTextArray("Single char", "a", "a"); + assertTextArray("Surrogate pair", PAIR1, PAIR1); + assertTextArray("Single escape", "\\", "\\"); + assertTextArray("Space", " ", " "); + assertTextArray("Single label", "abc", "abc"); + assertTextArray("Single surrogate pairs label", SURROGATE2, SURROGATE2); + assertTextArray("Spaces", " ", " "); + assertTextArray("Spaces in label", "a b c", "a b c"); + assertTextArray("Spaces at beginning of label", " abc", " abc"); + assertTextArray("Spaces at end of label", "abc ", "abc "); + assertTextArray("Label surrounded by spaces", " abc ", " abc "); + assertTextArray("Surrogate pair surrounded by space", + " " + PAIR1 + " ", + " " + PAIR1 + " "); + assertTextArray("Surrogate pair within characters", + "ab" + PAIR2 + "cd", + "ab" + PAIR2 + "cd"); + assertTextArray("Surrogate pairs within characters", + "ab" + SURROGATE1 + "cd", + "ab" + SURROGATE1 + "cd"); + + assertTextArray("Incomplete resource reference 1", "string", "string"); + assertTextArray("Incomplete resource reference 2", "@string", "@string"); + assertTextArray("Incomplete resource reference 3", "string/", "string/"); + assertTextArray("Incomplete resource reference 4", "@" + SURROGATE2, "@" + SURROGATE2); + } + + public void testParseCsvTextSingleEscaped() { + assertTextArray("Escaped char", "\\a", "\\a"); + assertTextArray("Escaped surrogate pair", "\\" + PAIR1, "\\" + PAIR1); + assertTextArray("Escaped comma", "\\,", "\\,"); + assertTextArray("Escaped comma escape", "a\\,\\", "a\\,\\"); + assertTextArray("Escaped escape", "\\\\", "\\\\"); + assertTextArray("Escaped label", "a\\bc", "a\\bc"); + assertTextArray("Escaped surrogate", "a\\" + PAIR1 + "c", "a\\" + PAIR1 + "c"); + assertTextArray("Escaped label at beginning", "\\abc", "\\abc"); + assertTextArray("Escaped surrogate at beginning", "\\" + SURROGATE2, "\\" + SURROGATE2); + assertTextArray("Escaped label at end", "abc\\", "abc\\"); + assertTextArray("Escaped surrogate at end", SURROGATE2 + "\\", SURROGATE2 + "\\"); + assertTextArray("Escaped label with comma", "a\\,c", "a\\,c"); + assertTextArray("Escaped surrogate with comma", + PAIR1 + "\\," + PAIR2, PAIR1 + "\\," + PAIR2); + assertTextArray("Escaped label with comma at beginning", "\\,bc", "\\,bc"); + assertTextArray("Escaped surrogate with comma at beginning", + "\\," + SURROGATE1, "\\," + SURROGATE1); + assertTextArray("Escaped label with comma at end", "ab\\,", "ab\\,"); + assertTextArray("Escaped surrogate with comma at end", + SURROGATE2 + "\\,", SURROGATE2 + "\\,"); + assertTextArray("Escaped label with successive", "\\,\\\\bc", "\\,\\\\bc"); + assertTextArray("Escaped surrogate with successive", + "\\,\\\\" + SURROGATE1, "\\,\\\\" + SURROGATE1); + assertTextArray("Escaped label with escape", "a\\\\c", "a\\\\c"); + assertTextArray("Escaped surrogate with escape", + PAIR1 + "\\\\" + PAIR2, PAIR1 + "\\\\" + PAIR2); + + assertTextArray("Escaped @string", "\\@string", "\\@string"); + assertTextArray("Escaped @string/", "\\@string/", "\\@string/"); + assertTextArray("Escaped @string/", "\\@string/empty_string", "\\@string/empty_string"); + } + + public void testParseCsvTextMulti() { + assertTextArray("Multiple chars", "a,b,c", "a", "b", "c"); + assertTextArray("Multiple chars", "a,b,\\c", "a", "b", "\\c"); + assertTextArray("Multiple chars and escape at beginning and end", + "\\a,b,\\c\\", "\\a", "b", "\\c\\"); + assertTextArray("Multiple surrogates", PAIR1 + "," + PAIR2 + "," + PAIR3, + PAIR1, PAIR2, PAIR3); + assertTextArray("Multiple chars surrounded by spaces", " a , b , c ", " a ", " b ", " c "); + assertTextArray("Multiple labels", "abc,def,ghi", "abc", "def", "ghi"); + assertTextArray("Multiple surrogated", SURROGATE1 + "," + SURROGATE2, + SURROGATE1, SURROGATE2); + assertTextArray("Multiple labels surrounded by spaces", " abc , def , ghi ", + " abc ", " def ", " ghi "); + } + + public void testParseCsvTextMultiEscaped() { + assertTextArray("Multiple chars with comma", "a,\\,,c", "a", "\\,", "c"); + assertTextArray("Multiple chars with comma surrounded by spaces", " a , \\, , c ", + " a ", " \\, ", " c "); + assertTextArray("Multiple labels with escape", + "\\abc,d\\ef,gh\\i", "\\abc", "d\\ef", "gh\\i"); + assertTextArray("Multiple labels with escape surrounded by spaces", + " \\abc , d\\ef , gh\\i ", " \\abc ", " d\\ef ", " gh\\i "); + assertTextArray("Multiple labels with comma and escape", + "ab\\\\,d\\\\\\,,g\\,i", "ab\\\\", "d\\\\\\,", "g\\,i"); + assertTextArray("Multiple labels with comma and escape surrounded by spaces", + " ab\\\\ , d\\\\\\, , g\\,i ", " ab\\\\ ", " d\\\\\\, ", " g\\,i "); + + assertTextArray("Multiple escaped @string", "\\@,\\@string/empty_string", + "\\@", "\\@string/empty_string"); + } + + public void testParseCsvResourceError() { + assertError("Incomplete resource name", "@string/", "@string/"); + assertError("Non existing resource", "@string/non_existing"); + } + + public void testParseCsvResourceZero() { + assertTextArray("Empty string", + "@string/empty_string"); + } + + public void testParseCsvResourceSingle() { + assertTextArray("Single char", + "@string/single_char", "a"); + assertTextArray("Space", + "@string/space", " "); + assertTextArray("Single label", + "@string/single_label", "abc"); + assertTextArray("Spaces", + "@string/spaces", " "); + assertTextArray("Spaces in label", + "@string/spaces_in_label", "a b c"); + assertTextArray("Spaces at beginning of label", + "@string/spaces_at_beginning_of_label", " abc"); + assertTextArray("Spaces at end of label", + "@string/spaces_at_end_of_label", "abc "); + assertTextArray("label surrounded by spaces", + "@string/label_surrounded_by_spaces", " abc "); + + assertTextArray("Escape and single char", + "\\\\@string/single_char", "\\\\a"); + } + + public void testParseCsvResourceSingleEscaped() { + assertTextArray("Escaped char", + "@string/escaped_char", "\\a"); + assertTextArray("Escaped comma", + "@string/escaped_comma", "\\,"); + assertTextArray("Escaped comma escape", + "@string/escaped_comma_escape", "a\\,\\"); + assertTextArray("Escaped escape", + "@string/escaped_escape", "\\\\"); + assertTextArray("Escaped label", + "@string/escaped_label", "a\\bc"); + assertTextArray("Escaped label at beginning", + "@string/escaped_label_at_beginning", "\\abc"); + assertTextArray("Escaped label at end", + "@string/escaped_label_at_end", "abc\\"); + assertTextArray("Escaped label with comma", + "@string/escaped_label_with_comma", "a\\,c"); + assertTextArray("Escaped label with comma at beginning", + "@string/escaped_label_with_comma_at_beginning", "\\,bc"); + assertTextArray("Escaped label with comma at end", + "@string/escaped_label_with_comma_at_end", "ab\\,"); + assertTextArray("Escaped label with successive", + "@string/escaped_label_with_successive", "\\,\\\\bc"); + assertTextArray("Escaped label with escape", + "@string/escaped_label_with_escape", "a\\\\c"); + } + + public void testParseCsvResourceMulti() { + assertTextArray("Multiple chars", + "@string/multiple_chars", "a", "b", "c"); + assertTextArray("Multiple chars surrounded by spaces", + "@string/multiple_chars_surrounded_by_spaces", + " a ", " b ", " c "); + assertTextArray("Multiple labels", + "@string/multiple_labels", "abc", "def", "ghi"); + assertTextArray("Multiple labels surrounded by spaces", + "@string/multiple_labels_surrounded_by_spaces", " abc ", " def ", " ghi "); + } + + public void testParseCsvResourcetMultiEscaped() { + assertTextArray("Multiple chars with comma", + "@string/multiple_chars_with_comma", + "a", "\\,", "c"); + assertTextArray("Multiple chars with comma surrounded by spaces", + "@string/multiple_chars_with_comma_surrounded_by_spaces", + " a ", " \\, ", " c "); + assertTextArray("Multiple labels with escape", + "@string/multiple_labels_with_escape", + "\\abc", "d\\ef", "gh\\i"); + assertTextArray("Multiple labels with escape surrounded by spaces", + "@string/multiple_labels_with_escape_surrounded_by_spaces", + " \\abc ", " d\\ef ", " gh\\i "); + assertTextArray("Multiple labels with comma and escape", + "@string/multiple_labels_with_comma_and_escape", + "ab\\\\", "d\\\\\\,", "g\\,i"); + assertTextArray("Multiple labels with comma and escape surrounded by spaces", + "@string/multiple_labels_with_comma_and_escape_surrounded_by_spaces", + " ab\\\\ ", " d\\\\\\, ", " g\\,i "); + } + + public void testParseMultipleResources() { + assertTextArray("Literals and resources", + "1,@string/multiple_chars,z", "1", "a", "b", "c", "z"); + assertTextArray("Literals and resources and escape at end", + "\\1,@string/multiple_chars,z\\", "\\1", "a", "b", "c", "z\\"); + assertTextArray("Multiple single resource chars and labels", + "@string/single_char,@string/single_label,@string/escaped_comma", + "a", "abc", "\\,"); + assertTextArray("Multiple single resource chars and labels 2", + "@string/single_char,@string/single_label,@string/escaped_comma_escape", + "a", "abc", "a\\,\\"); + assertTextArray("Multiple multiple resource chars and labels", + "@string/multiple_chars,@string/multiple_labels,@string/multiple_chars_with_comma", + "a", "b", "c", "abc", "def", "ghi", "a", "\\,", "c"); + assertTextArray("Concatenated resources", + "@string/multiple_chars@string/multiple_labels@string/multiple_chars_with_comma", + "a", "b", "cabc", "def", "ghia", "\\,", "c"); + assertTextArray("Concatenated resource and literal", + "abc@string/multiple_labels", + "abcabc", "def", "ghi"); + } + + public void testParseIndirectReference() { + assertTextArray("Indirect", + "@string/indirect_string", "a", "b", "c"); + assertTextArray("Indirect with literal", + "1,@string/indirect_string_with_literal,2", "1", "x", "a", "b", "c", "y", "2"); + } + + public void testParseInfiniteIndirectReference() { + assertError("Infinite indirection", + "1,@string/infinite_indirection,2", "1", "infinite", "<infinite>", "loop", "2"); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java new file mode 100644 index 000000000..07f5848b2 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java @@ -0,0 +1,469 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.keyboard.internal; + +import android.content.res.Resources; +import android.test.AndroidTestCase; + +import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.latin.R; + +import java.util.Arrays; + +public class KeySpecParserTests extends AndroidTestCase { + private Resources mRes; + + private static final int ICON_UNDEFINED = KeyboardIconsSet.ICON_UNDEFINED; + + private static final String CODE_SETTINGS_RES = "integer/key_settings"; + private static final String ICON_SETTINGS_NAME = "settingsKey"; + + private static final String CODE_SETTINGS = "@" + CODE_SETTINGS_RES; + private static final String ICON_SETTINGS = "@icon/" + ICON_SETTINGS_NAME; + private static final String CODE_NON_EXISTING = "@integer/non_existing"; + private static final String ICON_NON_EXISTING = "@icon/non_existing"; + + private int mCodeSettings; + private int mSettingsIconId; + + @Override + protected void setUp() { + Resources res = getContext().getResources(); + mRes = res; + + final String packageName = res.getResourcePackageName(R.string.english_ime_name); + final int codeId = res.getIdentifier(CODE_SETTINGS_RES, null, packageName); + mCodeSettings = res.getInteger(codeId); + mSettingsIconId = KeyboardIconsSet.getIconId(ICON_SETTINGS_NAME); + } + + private void assertParser(String message, String moreKeySpec, String expectedLabel, + String expectedOutputText, int expectedIcon, int expectedCode) { + String actualLabel = KeySpecParser.getLabel(moreKeySpec); + assertEquals(message + ": label:", expectedLabel, actualLabel); + + String actualOutputText = KeySpecParser.getOutputText(moreKeySpec); + assertEquals(message + ": ouptputText:", expectedOutputText, actualOutputText); + + int actualIcon = KeySpecParser.getIconId(moreKeySpec); + assertEquals(message + ": icon:", expectedIcon, actualIcon); + + int actualCode = KeySpecParser.getCode(mRes, moreKeySpec); + assertEquals(message + ": codes value:", expectedCode, actualCode); + } + + private void assertParserError(String message, String moreKeySpec, String expectedLabel, + String expectedOutputText, int expectedIcon, int expectedCode) { + try { + assertParser(message, moreKeySpec, expectedLabel, expectedOutputText, expectedIcon, + expectedCode); + fail(message); + } catch (Exception pcpe) { + // success. + } + } + + // \U001d11e: MUSICAL SYMBOL G CLEF + private static final String PAIR1 = "\ud834\udd1e"; + private static final int CODE1 = PAIR1.codePointAt(0); + // \U001d122: MUSICAL SYMBOL F CLEF + private static final String PAIR2 = "\ud834\udd22"; + private static final int CODE2 = PAIR2.codePointAt(0); + // \U002f8a6: CJK COMPATIBILITY IDEOGRAPH-2F8A6; variant character of \u6148. + private static final String PAIR3 = "\ud87e\udca6"; + private static final String SURROGATE1 = PAIR1 + PAIR2; + private static final String SURROGATE2 = PAIR1 + PAIR2 + PAIR3; + + public void testSingleLetter() { + assertParser("Single letter", "a", + "a", null, ICON_UNDEFINED, 'a'); + assertParser("Single surrogate", PAIR1, + PAIR1, null, ICON_UNDEFINED, CODE1); + assertParser("Single escaped bar", "\\|", + "|", null, ICON_UNDEFINED, '|'); + assertParser("Single escaped escape", "\\\\", + "\\", null, ICON_UNDEFINED, '\\'); + assertParser("Single comma", ",", + ",", null, ICON_UNDEFINED, ','); + assertParser("Single escaped comma", "\\,", + ",", null, ICON_UNDEFINED, ','); + assertParser("Single escaped letter", "\\a", + "a", null, ICON_UNDEFINED, 'a'); + assertParser("Single escaped surrogate", "\\" + PAIR2, + PAIR2, null, ICON_UNDEFINED, CODE2); + assertParser("Single at", "@", + "@", null, ICON_UNDEFINED, '@'); + assertParser("Single escaped at", "\\@", + "@", null, ICON_UNDEFINED, '@'); + assertParser("Single output text letter", "a|a", + "a", null, ICON_UNDEFINED, 'a'); + assertParser("Single surrogate pair outputText", "G Clef|" + PAIR1, + "G Clef", null, ICON_UNDEFINED, CODE1); + assertParser("Single letter with outputText", "a|abc", + "a", "abc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Single letter with surrogate outputText", "a|" + SURROGATE1, + "a", SURROGATE1, ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Single surrogate with outputText", PAIR3 + "|abc", + PAIR3, "abc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Single letter with escaped outputText", "a|a\\|c", + "a", "a|c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Single letter with escaped surrogate outputText", + "a|" + PAIR1 + "\\|" + PAIR2, + "a", PAIR1 + "|" + PAIR2, ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Single letter with comma outputText", "a|a,b", + "a", "a,b", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Single letter with escaped comma outputText", "a|a\\,b", + "a", "a,b", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Single letter with outputText starts with at", "a|@bc", + "a", "@bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Single letter with surrogate outputText starts with at", "a|@" + SURROGATE2, + "a", "@" + SURROGATE2, ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Single letter with outputText contains at", "a|a@c", + "a", "a@c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Single letter with escaped at outputText", "a|\\@bc", + "a", "@bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Single escaped escape with single outputText", "\\\\|\\\\", + "\\", null, ICON_UNDEFINED, '\\'); + assertParser("Single escaped bar with single outputText", "\\||\\|", + "|", null, ICON_UNDEFINED, '|'); + assertParser("Single letter with code", "a|" + CODE_SETTINGS, + "a", null, ICON_UNDEFINED, mCodeSettings); + } + + public void testLabel() { + assertParser("Simple label", "abc", + "abc", "abc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Simple surrogate label", SURROGATE1, + SURROGATE1, SURROGATE1, ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label with escaped bar", "a\\|c", + "a|c", "a|c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Surrogate label with escaped bar", PAIR1 + "\\|" + PAIR2, + PAIR1 + "|" + PAIR2, PAIR1 + "|" + PAIR2, + ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label with escaped escape", "a\\\\c", + "a\\c", "a\\c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label with comma", "a,c", + "a,c", "a,c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label with escaped comma", "a\\,c", + "a,c", "a,c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label starts with at", "@bc", + "@bc", "@bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Surrogate label starts with at", "@" + SURROGATE1, + "@" + SURROGATE1, "@" + SURROGATE1, ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label contains at", "a@c", + "a@c", "a@c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label with escaped at", "\\@bc", + "@bc", "@bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label with escaped letter", "\\abc", + "abc", "abc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label with outputText", "abc|def", + "abc", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label with comma and outputText", "a,c|def", + "a,c", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Escaped comma label with outputText", "a\\,c|def", + "a,c", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Escaped label with outputText", "a\\|c|def", + "a|c", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label with escaped bar outputText", "abc|d\\|f", + "abc", "d|f", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Escaped escape label with outputText", "a\\\\|def", + "a\\", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label starts with at and outputText", "@bc|def", + "@bc", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label contains at label and outputText", "a@c|def", + "a@c", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Escaped at label with outputText", "\\@bc|def", + "@bc", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label with comma outputText", "abc|a,b", + "abc", "a,b", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label with escaped comma outputText", "abc|a\\,b", + "abc", "a,b", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label with outputText starts with at", "abc|@bc", + "abc", "@bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label with outputText contains at", "abc|a@c", + "abc", "a@c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label with escaped at outputText", "abc|\\@bc", + "abc", "@bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label with escaped bar outputText", "abc|d\\|f", + "abc", "d|f", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Escaped bar label with escaped bar outputText", "a\\|c|d\\|f", + "a|c", "d|f", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label with code", "abc|" + CODE_SETTINGS, + "abc", null, ICON_UNDEFINED, mCodeSettings); + assertParser("Escaped label with code", "a\\|c|" + CODE_SETTINGS, + "a|c", null, ICON_UNDEFINED, mCodeSettings); + } + + public void testIconAndCode() { + assertParser("Icon with outputText", ICON_SETTINGS + "|abc", + null, "abc", mSettingsIconId, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Icon with outputText starts with at", ICON_SETTINGS + "|@bc", + null, "@bc", mSettingsIconId, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Icon with outputText contains at", ICON_SETTINGS + "|a@c", + null, "a@c", mSettingsIconId, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Icon with escaped at outputText", ICON_SETTINGS + "|\\@bc", + null, "@bc", mSettingsIconId, Keyboard.CODE_OUTPUT_TEXT); + assertParser("Label starts with at and code", "@bc|" + CODE_SETTINGS, + "@bc", null, ICON_UNDEFINED, mCodeSettings); + assertParser("Label contains at and code", "a@c|" + CODE_SETTINGS, + "a@c", null, ICON_UNDEFINED, mCodeSettings); + assertParser("Escaped at label with code", "\\@bc|" + CODE_SETTINGS, + "@bc", null, ICON_UNDEFINED, mCodeSettings); + assertParser("Icon with code", ICON_SETTINGS + "|" + CODE_SETTINGS, + null, null, mSettingsIconId, mCodeSettings); + } + + public void testFormatError() { + assertParserError("Empty spec", "", null, + null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); + assertParserError("Empty label with outputText", "|a", + null, "a", ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); + assertParserError("Empty label with code", "|" + CODE_SETTINGS, + null, null, ICON_UNDEFINED, mCodeSettings); + assertParserError("Empty outputText with label", "a|", + "a", null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); + assertParserError("Empty outputText with icon", ICON_SETTINGS + "|", + null, null, mSettingsIconId, Keyboard.CODE_UNSPECIFIED); + assertParserError("Empty icon and code", "|", + null, null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); + assertParserError("Icon without code", ICON_SETTINGS, + null, null, mSettingsIconId, Keyboard.CODE_UNSPECIFIED); + assertParserError("Non existing icon", ICON_NON_EXISTING + "|abc", + null, "abc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT); + assertParserError("Non existing code", "abc|" + CODE_NON_EXISTING, + "abc", null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); + assertParserError("Third bar at end", "a|b|", + "a", null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); + assertParserError("Multiple bar", "a|b|c", + "a", null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); + assertParserError("Multiple bar with label and code", "a|" + CODE_SETTINGS + "|c", + "a", null, ICON_UNDEFINED, mCodeSettings); + assertParserError("Multiple bar with icon and outputText", ICON_SETTINGS + "|b|c", + null, null, mSettingsIconId, Keyboard.CODE_UNSPECIFIED); + assertParserError("Multiple bar with icon and code", + ICON_SETTINGS + "|" + CODE_SETTINGS + "|c", + null, null, mSettingsIconId, mCodeSettings); + } + + private static void assertMoreKeys(String message, String[] moreKeys, + String[] additionalMoreKeys, String[] expected) { + final String[] actual = KeySpecParser.insertAddtionalMoreKeys( + moreKeys, additionalMoreKeys); + if (expected == null && actual == null) { + return; + } + if (expected == null || actual == null) { + assertEquals(message, Arrays.toString(expected), Arrays.toString(actual)); + } else { + if (expected.length != actual.length) { + assertEquals(message, Arrays.toString(expected), Arrays.toString(actual)); + } + for (int i = 0; i < expected.length; i++) { + if (!actual[i].equals(expected[i])) { + assertEquals(message, Arrays.toString(expected), Arrays.toString(actual)); + } + } + } + } + + public void testInsertAdditionalMoreKeys() { + // Escaped marker. + assertMoreKeys("escaped marker", + new String[] { "\\%", "%-)" }, + new String[] { "1", "2" }, + new String[] { "1", "2", "\\%", "%-)" }); + + // 0 more key. + assertMoreKeys("null & null", null, null, null); + assertMoreKeys("null & 1 additional", + null, + new String[] { "1" }, + new String[] { "1" }); + assertMoreKeys("null & 2 additionals", + null, + new String[] { "1", "2" }, + new String[] { "1", "2" }); + + // 0 additional more key. + assertMoreKeys("1 more key & null", + new String[] { "A" }, + null, + new String[] { "A" }); + assertMoreKeys("2 more keys & null", + new String[] { "A", "B" }, + null, + new String[] { "A", "B" }); + + // No marker. + assertMoreKeys("1 more key & 1 addtional & no marker", + new String[] { "A" }, + new String[] { "1" }, + new String[] { "1", "A" }); + assertMoreKeys("1 more key & 2 addtionals & no marker", + new String[] { "A" }, + new String[] { "1", "2" }, + new String[] { "1", "2", "A" }); + assertMoreKeys("2 more keys & 1 addtional & no marker", + new String[] { "A", "B" }, + new String[] { "1" }, + new String[] { "1", "A", "B" }); + assertMoreKeys("2 more keys & 2 addtionals & no marker", + new String[] { "A", "B" }, + new String[] { "1", "2" }, + new String[] { "1", "2", "A", "B" }); + + // 1 marker. + assertMoreKeys("1 more key & 1 additional & marker at head", + new String[] { "%", "A" }, + new String[] { "1" }, + new String[] { "1", "A" }); + assertMoreKeys("1 more key & 1 additional & marker at tail", + new String[] { "A", "%" }, + new String[] { "1" }, + new String[] { "A", "1" }); + assertMoreKeys("2 more keys & 1 additional & marker at middle", + new String[] { "A", "%", "B" }, + new String[] { "1" }, + new String[] { "A", "1", "B" }); + + // 1 marker & excess additional more keys. + assertMoreKeys("1 more key & 2 additionals & marker at head", + new String[] { "%", "A", "B" }, + new String[] { "1", "2" }, + new String[] { "1", "A", "B", "2" }); + assertMoreKeys("1 more key & 2 additionals & marker at tail", + new String[] { "A", "B", "%" }, + new String[] { "1", "2" }, + new String[] { "A", "B", "1", "2" }); + assertMoreKeys("2 more keys & 2 additionals & marker at middle", + new String[] { "A", "%", "B" }, + new String[] { "1", "2" }, + new String[] { "A", "1", "B", "2" }); + + // 2 markers. + assertMoreKeys("0 more key & 2 addtional & 2 markers", + new String[] { "%", "%" }, + new String[] { "1", "2" }, + new String[] { "1", "2" }); + assertMoreKeys("1 more key & 2 addtional & 2 markers at head", + new String[] { "%", "%", "A" }, + new String[] { "1", "2" }, + new String[] { "1", "2", "A" }); + assertMoreKeys("1 more key & 2 addtional & 2 markers at tail", + new String[] { "A", "%", "%" }, + new String[] { "1", "2" }, + new String[] { "A", "1", "2" }); + assertMoreKeys("2 more keys & 2 addtional & 2 markers at middle", + new String[] { "A", "%", "%", "B" }, + new String[] { "1", "2" }, + new String[] { "A", "1", "2", "B" }); + assertMoreKeys("2 more keys & 2 addtional & 2 markers at head & middle", + new String[] { "%", "A", "%", "B" }, + new String[] { "1", "2" }, + new String[] { "1", "A", "2", "B" }); + assertMoreKeys("2 more keys & 2 addtional & 2 markers at head & tail", + new String[] { "%", "A", "B", "%" }, + new String[] { "1", "2" }, + new String[] { "1", "A", "B", "2" }); + assertMoreKeys("2 more keys & 2 addtional & 2 markers at middle & tail", + new String[] { "A", "%", "B", "%" }, + new String[] { "1", "2" }, + new String[] { "A", "1", "B", "2" }); + + // 2 markers & excess additional keys. + assertMoreKeys("0 more key & 2 addtional & 2 markers", + new String[] { "%", "%" }, + new String[] { "1", "2", "3" }, + new String[] { "1", "2", "3" }); + assertMoreKeys("1 more key & 2 addtional & 2 markers at head", + new String[] { "%", "%", "A" }, + new String[] { "1", "2", "3" }, + new String[] { "1", "2", "A", "3" }); + assertMoreKeys("1 more key & 2 addtional & 2 markers at tail", + new String[] { "A", "%", "%" }, + new String[] { "1", "2", "3" }, + new String[] { "A", "1", "2", "3" }); + assertMoreKeys("2 more keys & 2 addtional & 2 markers at middle", + new String[] { "A", "%", "%", "B" }, + new String[] { "1", "2", "3" }, + new String[] { "A", "1", "2", "B", "3" }); + assertMoreKeys("2 more keys & 2 addtional & 2 markers at head & middle", + new String[] { "%", "A", "%", "B" }, + new String[] { "1", "2", "3" }, + new String[] { "1", "A", "2", "B", "3" }); + assertMoreKeys("2 more keys & 2 addtional & 2 markers at head & tail", + new String[] { "%", "A", "B", "%" }, + new String[] { "1", "2", "3" }, + new String[] { "1", "A", "B", "2", "3" }); + assertMoreKeys("2 more keys & 2 addtional & 2 markers at middle & tail", + new String[] { "A", "%", "B", "%" }, + new String[] { "1", "2", "3" }, + new String[] { "A", "1", "B", "2", "3" }); + + // 0 addtional more key and excess markers. + assertMoreKeys("0 more key & null & excess marker", + new String[] { "%" }, + null, + null); + assertMoreKeys("1 more key & null & excess marker at head", + new String[] { "%", "A" }, + null, + new String[] { "A" }); + assertMoreKeys("1 more key & null & excess marker at tail", + new String[] { "A", "%" }, + null, + new String[] { "A" }); + assertMoreKeys("2 more keys & null & excess marker at middle", + new String[] { "A", "%", "B" }, + null, + new String[] { "A", "B" }); + assertMoreKeys("2 more keys & null & excess markers", + new String[] { "%", "A", "%", "B", "%" }, + null, + new String[] { "A", "B" }); + + // Excess markers. + assertMoreKeys("0 more key & 1 addtional & excess marker", + new String[] { "%", "%" }, + new String[] { "1" }, + new String[] { "1" }); + assertMoreKeys("1 more key & 1 addtional & excess marker at head", + new String[] { "%", "%", "A" }, + new String[] { "1" }, + new String[] { "1", "A" }); + assertMoreKeys("1 more key & 1 addtional & excess marker at tail", + new String[] { "A", "%", "%" }, + new String[] { "1" }, + new String[] { "A", "1" }); + assertMoreKeys("2 more keys & 1 addtional & excess marker at middle", + new String[] { "A", "%", "%", "B" }, + new String[] { "1" }, + new String[] { "A", "1", "B" }); + assertMoreKeys("2 more keys & 1 addtional & excess markers", + new String[] { "%", "A", "%", "B", "%" }, + new String[] { "1" }, + new String[] { "1", "A", "B" }); + assertMoreKeys("2 more keys & 2 addtionals & excess markers", + new String[] { "%", "A", "%", "B", "%" }, + new String[] { "1", "2" }, + new String[] { "1", "A", "2", "B" }); + assertMoreKeys("2 more keys & 3 addtionals & excess markers", + new String[] { "%", "A", "%", "%", "B", "%" }, + new String[] { "1", "2", "3" }, + new String[] { "1", "A", "2", "3", "B" }); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyStylesTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyStylesTests.java deleted file mode 100644 index 4050a7123..000000000 --- a/tests/src/com/android/inputmethod/keyboard/internal/KeyStylesTests.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.keyboard.internal; - -import com.android.inputmethod.keyboard.internal.KeyStyles.EmptyKeyStyle; - -import android.test.AndroidTestCase; -import android.text.TextUtils; - -public class KeyStylesTests extends AndroidTestCase { - private static String format(String message, Object expected, Object actual) { - return message + " expected:<" + expected + "> but was:<" + actual + ">"; - } - - private static void assertTextArray(String message, CharSequence value, - CharSequence ... expected) { - final CharSequence actual[] = EmptyKeyStyle.parseCsvText(value); - if (expected.length == 0) { - assertNull(message, actual); - return; - } - assertSame(message + ": result length", expected.length, actual.length); - for (int i = 0; i < actual.length; i++) { - final boolean equals = TextUtils.equals(expected[i], actual[i]); - assertTrue(format(message + ": result at " + i + ":", expected[i], actual[i]), equals); - } - } - - public void testParseCsvTextZero() { - assertTextArray("Empty string", ""); - } - - public void testParseCsvTextSingle() { - assertTextArray("Single char", "a", "a"); - assertTextArray("Space", " ", " "); - assertTextArray("Single label", "abc", "abc"); - assertTextArray("Spaces", " ", " "); - assertTextArray("Spaces in label", "a b c", "a b c"); - assertTextArray("Spaces at beginning of label", " abc", " abc"); - assertTextArray("Spaces at end of label", "abc ", "abc "); - assertTextArray("label surrounded by spaces", " abc ", " abc "); - } - - public void testParseCsvTextSingleEscaped() { - assertTextArray("Escaped char", "\\a", "a"); - assertTextArray("Escaped comma", "\\,", ","); - assertTextArray("Escaped escape", "\\\\", "\\"); - assertTextArray("Escaped label", "a\\bc", "abc"); - assertTextArray("Escaped label at begininng", "\\abc", "abc"); - assertTextArray("Escaped label with comma", "a\\,c", "a,c"); - assertTextArray("Escaped label with comma at beginning", "\\,bc", ",bc"); - assertTextArray("Escaped label with successive", "\\,\\\\bc", ",\\bc"); - assertTextArray("Escaped label with escape", "a\\\\c", "a\\c"); - } - - public void testParseCsvTextMulti() { - assertTextArray("Multiple chars", "a,b,c", "a", "b", "c"); - assertTextArray("Multiple chars surrounded by spaces", " a , b , c ", " a ", " b ", " c "); - assertTextArray("Multiple labels", "abc,def,ghi", "abc", "def", "ghi"); - assertTextArray("Multiple labels surrounded by spaces", " abc , def , ghi ", - " abc ", " def ", " ghi "); - } - - public void testParseCsvTextMultiEscaped() { - assertTextArray("Multiple chars with comma", "a,\\,,c", "a", ",", "c"); - assertTextArray("Multiple chars with comma surrounded by spaces", " a , \\, , c ", - " a ", " , ", " c "); - assertTextArray("Multiple labels with escape", "\\abc,d\\ef,gh\\i", "abc", "def", "ghi"); - assertTextArray("Multiple labels with escape surrounded by spaces", - " \\abc , d\\ef , gh\\i ", " abc ", " def ", " ghi "); - assertTextArray("Multiple labels with comma and escape", - "ab\\\\,d\\\\\\,,g\\,i", "ab\\", "d\\,", "g,i"); - assertTextArray("Multiple labels with comma and escape surrounded by spaces", - " ab\\\\ , d\\\\\\, , g\\,i ", " ab\\ ", " d\\, ", " g,i "); - } -} diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateMultiTouchTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateMultiTouchTests.java new file mode 100644 index 000000000..e9f37afee --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateMultiTouchTests.java @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2012 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; + +public class KeyboardStateMultiTouchTests extends KeyboardStateTestsBase { + // Chording input in alphabet. + public void testChordingAlphabet() { + // Press shift key and hold, enter into choring shift state. + pressKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED); + // Press/release letter key. + chordingPressAndReleaseKey('Z', ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + // Release shift key, switch back to alphabet. + releaseKey(CODE_SHIFT, ALPHABET_UNSHIFTED); + + // Press "?123" key and hold, enter into choring symbols state. + pressKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED); + // Press/release symbol letter key. + chordingPressAndReleaseKey('1', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Release "ABC" key, switch back to alphabet. + releaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED); + } + + // Chording input in shift locked. + public void testChordingShiftLocked() { + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + + // Press shift key and hold, enter into choring shift state. + pressKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED); + // Press/release letter key. + chordingPressAndReleaseKey('Z', ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_SHIFT_LOCK_SHIFTED); + // Release shift key, switch back to alphabet shift locked. + releaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCKED); + + // Press "?123" key and hold, enter into choring symbols state. + pressKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED); + // Press/release symbol letter key. + chordingPressAndReleaseKey('1', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Release "123?" key, switch back to alphabet shift locked. + releaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED); + } + + // Chording input in symbols. + public void testChordingSymbols() { + // Press/release "?123" key, enter symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + + // Press "=\<" key and hold, enter into choring symbols shifted state. + pressKey(CODE_SHIFT, SYMBOLS_SHIFTED); + // Press/release symbol letter key. + chordingPressAndReleaseKey('1', SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Release "=\<" key, switch back to symbols. + releaseKey(CODE_SHIFT, SYMBOLS_UNSHIFTED); + + // Press "ABC" key and hold, enter into choring alphabet state. + pressKey(CODE_SYMBOL, ALPHABET_UNSHIFTED); + // Press/release letter key. + chordingPressAndReleaseKey('a', ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + // Release "ABC" key, switch back to symbols. + releaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED); + + // Alphabet shifted -> symbols -> "ABC" key + letter -> symbols + // -> alphabet. + // Load keyboard + loadKeyboard(ALPHABET_UNSHIFTED); + // Press/release shift key, enter alphabet shifted. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press "ABC" key, enter into chording alphabet state. + pressKey(CODE_SYMBOL, ALPHABET_UNSHIFTED); + // Enter/release letter key. + chordingPressAndReleaseKey('a', ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + // Release "ABC" key, switch back to symbols. + releaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED); + // Press/release "ABC" key, switch to alphabet (not alphabet shifted). + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + + // Alphabet shift locked -> symbols -> "ABC" key + letter -> symbols -> + // alphabet shift locked. + // Load keyboard + loadKeyboard(ALPHABET_UNSHIFTED); + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press "ABC" key, enter into chording alphabet shift locked. + pressKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED); + // Enter/release letter key. + chordingPressAndReleaseKey('A', ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + // Release "ABC" key, switch back to symbols. + releaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED); + // Press/release "ABC" key, switch to alphabet shift locked. + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + + // Alphabet shift locked -> symbols -> "=\<" key + letter -> symbols -> + // alphabet shift locked. + // Load keyboard + loadKeyboard(ALPHABET_UNSHIFTED); + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press "=\<" key, enter into symbols shifted chording state. + pressKey(CODE_SHIFT, SYMBOLS_SHIFTED); + // Enter/release symbols shift letter key. + chordingPressAndReleaseKey('~', SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Release "=\<" key, switch back to symbols. + releaseKey(CODE_SHIFT, SYMBOLS_UNSHIFTED); + // Press/release "ABC" key, switch to alphabet shift locked. + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + } + + // Chording input in symbol shifted. + public void testChordingSymbolsShifted() { + // Press/release "?123" key, enter symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "=\<" key, enter symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + + // Press "?123" key and hold, enter into chording symbols state. + pressKey(CODE_SHIFT, SYMBOLS_UNSHIFTED); + // Press/release symbol letter key. + chordingPressAndReleaseKey('1', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Release "=\<" key, switch back to symbols shifted state. + releaseKey(CODE_SHIFT, SYMBOLS_SHIFTED); + + // Press "ABC" key and hold, enter into choring alphabet state. + pressKey(CODE_SYMBOL, ALPHABET_UNSHIFTED); + // Press/release letter key. + chordingPressAndReleaseKey('a', ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + // Release "ABC" key, switch back to symbols. + releaseKey(CODE_SYMBOL, SYMBOLS_SHIFTED); + + // Alphabet shifted -> symbols shifted -> "ABC" key + letter -> symbols shifted -> + // alphabet. + // Load keyboard + loadKeyboard(ALPHABET_UNSHIFTED); + // Press/release shift key, enter alphabet shifted. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "=\<" key, enter symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Press "ABC" key, enter into chording alphabet state. + pressKey(CODE_SYMBOL, ALPHABET_UNSHIFTED); + // Enter/release letter key. + chordingPressAndReleaseKey('a', ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + // Release "ABC" key, switch back to symbols shifted. + releaseKey(CODE_SYMBOL, SYMBOLS_SHIFTED); + // Press/release "ABC" key, switch to alphabet (not alphabet shifted). + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + + // Alphabet shift locked -> symbols shifted -> "ABC" key + letter -> symbols shifted + // -> alphabet shift locked. + // Load keyboard + loadKeyboard(ALPHABET_UNSHIFTED); + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "=\<" key, enter symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Press "ABC" key, enter into chording alphabet shift locked. + pressKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED); + // Enter/release letter key. + chordingPressAndReleaseKey('A', ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + // Release "ABC" key, switch back to symbols shifted. + releaseKey(CODE_SYMBOL, SYMBOLS_SHIFTED); + // Press/release "ABC" key, switch to alphabet shift locked. + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + + // Alphabet shift locked -> symbols shifted -> "=\<" key + letter -> symbols shifted + // -> alphabet shift locked. + // Load keyboard + loadKeyboard(ALPHABET_UNSHIFTED); + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "=\<" key, enter symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Press "=\<" key, enter into symbols chording state. + pressKey(CODE_SHIFT, SYMBOLS_UNSHIFTED); + // Enter/release symbols letter key. + chordingPressAndReleaseKey('1', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Release "=\<" key, switch back to symbols shifted. + releaseKey(CODE_SHIFT, SYMBOLS_SHIFTED); + // Press/release "ABC" key, switch to alphabet shift locked. + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + } + + // Chording input in automatic upper case. + public void testChordingAutomaticUpperCase() { + // Set auto caps mode on. + setAutoCapsMode(AUTO_CAPS); + + // Update shift state with auto caps enabled. + pressAndReleaseKey(CODE_AUTO_CAPS_TRIGGER, ALPHABET_UNSHIFTED, ALPHABET_AUTOMATIC_SHIFTED); + // Press shift key and hold, enter into chording shift state. + pressKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED); + // Press/release letter key. + chordingPressAndReleaseKey('Z', ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + // Release shift key, switch back to alphabet. + releaseKey(CODE_SHIFT, ALPHABET_UNSHIFTED); + + // Update shift state with auto caps enabled. + pressAndReleaseKey(CODE_AUTO_CAPS_TRIGGER, ALPHABET_UNSHIFTED, ALPHABET_AUTOMATIC_SHIFTED); + // Press "123?" key and hold, enter into chording symbols state. + pressKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED); + // Press/release symbol letter key. + chordingPressAndReleaseKey('1', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Release "123?" key, switch back to alphabet. + releaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java new file mode 100644 index 000000000..8c53fb5c8 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java @@ -0,0 +1,690 @@ +/* + * Copyright (C) 2012 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; + +public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase { + // Shift key in alphabet. + public void testShiftAlphabet() { + // Press/release shift key, enter into alphabet shifted. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + + // Press/release shift key, back to alphabet. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED); + + // Press/release shift key, enter into alphabet shifted. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + // Press/release letter key, switch back to alphabet. + pressAndReleaseKey('Z', ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED); + } + + // Shift key in symbols. + public void testShiftSymbols() { + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + + // Press/release "=\<" key, enter into symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + + // Press/release "?123" key, back to symbols. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + + // Press/release "=\<" key, enter into symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Press/release symbol letter key, remain in symbols shifted. + pressAndReleaseKey('1', SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + } + + // Switching between alphabet and symbols. + public void testAlphabetAndSymbols() { + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "ABC" key, back to alphabet. + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + + // Press/release "=\<" key, enter into symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Press/release "ABC" key, back to alphabet. + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + // Press/release "?123" key, back to symbols (not symbols shifted). + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + } + + // Switching between alphabet shifted and symbols. + public void testAlphabetShiftedAndSymbols() { + // Press/release shift key, enter into alphabet shifted. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "ABC" key, back to alphabet (not alphabet shifted). + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + + // Press/release shift key, enter into alphabet shifted. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "=\< key, enter into symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Press/release "ABC" key, back to alphabet (not alphabet shifted). + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + } + + // Switching between alphabet shift locked and symbols. + public void testAlphabetShiftLockedAndSymbols() { + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "ABC" key, back to alphabet shift locked. + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + + // Press/release "=\<" key, enter into symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Press/release "ABC" key, back to alphabet shift locked. + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + // Press/release "?123" key, back to symbols (not symbols shifted). + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + } + + // Automatic switch back to alphabet by space key. + public void testSwitchBackBySpace() { + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Enter symbol letter. + pressAndReleaseKey('1', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Enter space, switch back to alphabet. + pressAndReleaseKey(CODE_SPACE, SYMBOLS_UNSHIFTED, ALPHABET_UNSHIFTED); + + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "=\<" key, enter into symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Enter symbol shift letter. + pressAndReleaseKey('~', SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Enter space, switch back to alphabet. + pressAndReleaseKey(CODE_SPACE, SYMBOLS_SHIFTED, ALPHABET_UNSHIFTED); + } + + // Automatic switch back to alphabet shift locked test by space key. + public void testSwitchBackBySpaceShiftLocked() { + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Enter symbol letter. + pressAndReleaseKey('1', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Enter space, switch back to alphabet shift locked. + pressAndReleaseKey(CODE_SPACE, SYMBOLS_UNSHIFTED, ALPHABET_SHIFT_LOCKED); + + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "=\<" key, enter into symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Enter symbol shift letter. + pressAndReleaseKey('~', SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Enter space, switch back to alphabet shift locked. + pressAndReleaseKey(CODE_SPACE, SYMBOLS_SHIFTED, ALPHABET_SHIFT_LOCKED); + } + + // Automatic switch back to alphabet by registered letters. + public void testSwitchBackChar() { + // Set switch back chars. + final String switchBackSymbols = "'"; + final int switchBackCode = switchBackSymbols.codePointAt(0); + setLayoutSwitchBackSymbols(switchBackSymbols); + loadKeyboard(ALPHABET_UNSHIFTED); + + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Enter symbol letter. + pressAndReleaseKey('1', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Enter switch back letter, switch back to alphabet. + pressAndReleaseKey(switchBackCode, SYMBOLS_UNSHIFTED, ALPHABET_UNSHIFTED); + + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "=\<" key, enter into symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Enter symbol shift letter. + pressAndReleaseKey('~', SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Enter switch abck letter, switch back to alphabet. + pressAndReleaseKey(switchBackCode, SYMBOLS_SHIFTED, ALPHABET_UNSHIFTED); + } + + // Automatic switch back to alphabet shift locked by registered letters. + public void testSwitchBackCharShiftLocked() { + // Set switch back chars. + final String switchBackSymbols = "'"; + final int switchBackCode = switchBackSymbols.codePointAt(0); + setLayoutSwitchBackSymbols(switchBackSymbols); + loadKeyboard(ALPHABET_UNSHIFTED); + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Enter symbol letter. + pressAndReleaseKey('1', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Enter switch back letter, switch back to alphabet shift locked. + pressAndReleaseKey(switchBackCode, SYMBOLS_UNSHIFTED, ALPHABET_SHIFT_LOCKED); + + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "=\<" key, enter into symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Enter symbol shift letter. + pressAndReleaseKey(CODE_SPACE, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Enter switch back letter, switch back to alphabet shift locked. + pressAndReleaseKey(switchBackCode, SYMBOLS_SHIFTED, ALPHABET_SHIFT_LOCKED); + } + + // Automatic upper case test + public void testAutomaticUpperCase() { + // Set auto caps mode on. + setAutoCapsMode(AUTO_CAPS); + // Load keyboard, should be in automatic shifted. + loadKeyboard(ALPHABET_AUTOMATIC_SHIFTED); + + // Press/release letter key, switch to alphabet. + pressAndReleaseKey('A', ALPHABET_AUTOMATIC_SHIFTED, ALPHABET_UNSHIFTED); + // Press/release auto caps trigger letter, should be in automatic shifted. + pressAndReleaseKey(CODE_AUTO_CAPS_TRIGGER, ALPHABET_UNSHIFTED, ALPHABET_AUTOMATIC_SHIFTED); + + // Press/release shift key, back to alphabet. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED); + // Press/release letter key, remain in alphabet. + pressAndReleaseKey('a', ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + // Press/release auto caps trigger letter, should be in automatic shifted. + pressAndReleaseKey(CODE_AUTO_CAPS_TRIGGER, ALPHABET_UNSHIFTED, ALPHABET_AUTOMATIC_SHIFTED); + + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release symbol letter key, remain in symbols. + pressAndReleaseKey('1', SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release space, switch back to automatic shifted. + pressAndReleaseKey(CODE_SPACE, SYMBOLS_UNSHIFTED, ALPHABET_AUTOMATIC_SHIFTED); + + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "=\<" key, enter into symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Press/release symbol shift letter key, remain in symbols shifted. + pressAndReleaseKey('~', SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Press/release space, switch back to automatic shifted. + pressAndReleaseKey(CODE_SPACE, SYMBOLS_SHIFTED, ALPHABET_AUTOMATIC_SHIFTED); + } + + // Long press shift key. + public void testLongPressShift() { + // Set auto caps mode off. + setAutoCapsMode(NO_AUTO_CAPS); + // Load keyboard, should be in alphabet. + loadKeyboard(ALPHABET_UNSHIFTED); + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Press/release shift key, back to alphabet. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_UNSHIFTED); + + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Press/release letter key, remain in shift locked. + pressAndReleaseKey('A', ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + // Press/release word separator, remain in shift locked. + pressAndReleaseKey(CODE_SPACE, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + // Press/release shift key, back to alphabet. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_UNSHIFTED); + + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Long press shift key, back to alphabet. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_UNSHIFTED); + + // Press/release shift key, enter alphabet shifted. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Press/release shift key, back to alphabet. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_UNSHIFTED); + + // Set auto caps mode on. + setAutoCapsMode(AUTO_CAPS); + // Load keyboard, should be in automatic shifted. + loadKeyboard(ALPHABET_AUTOMATIC_SHIFTED); + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Press/release shift key, back to alphabet. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_UNSHIFTED); + } + + // Double tap shift key. + public void testDoubleTapShift() { + // First shift key tap. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + // Second shift key tap. + secondPressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + + // First shift key tap. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_UNSHIFTED); + // Second shift key tap. + secondPressAndReleaseKey(CODE_SHIFT, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + + // Press/release shift key, enter alphabet manual shifted. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + + // First shift key tap. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED); + // Second shift key tap. + secondPressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + + // First shift key tap. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_UNSHIFTED); + // Second shift key tap. + secondPressAndReleaseKey(CODE_SHIFT, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + + // Set auto caps mode on. + setAutoCapsMode(AUTO_CAPS); + // Load keyboard, should be in automatic shifted. + loadKeyboard(ALPHABET_AUTOMATIC_SHIFTED); + + // First shift key tap. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED); + // Second shift key tap. + secondPressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + + // First shift key tap. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_UNSHIFTED); + // Second shift key tap. + secondPressAndReleaseKey(CODE_SHIFT, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + } + + // Update shift state. + public void testUpdateShiftState() { + // Set auto caps mode off. + setAutoCapsMode(NO_AUTO_CAPS); + // Load keyboard, should be in alphabet. + loadKeyboard(ALPHABET_UNSHIFTED); + // Update shift state, remained in alphabet. + updateShiftState(ALPHABET_UNSHIFTED); + + // Press/release shift key, enter alphabet shifted. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + // Update shift state, back to alphabet. + updateShiftState(ALPHABET_UNSHIFTED); + + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Update shift state, remained in alphabet shift locked. + updateShiftState(ALPHABET_SHIFT_LOCKED); + // Long press shift key, back to alphabet. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_UNSHIFTED); + + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Update shift state, remained in symbols. + updateShiftState(SYMBOLS_UNSHIFTED); + + // Press/release "=\<" key, enter symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Update shift state, remained in symbols shifted. + updateShiftState(SYMBOLS_SHIFTED); + + // Set auto caps mode on. + setAutoCapsMode(AUTO_CAPS); + // Load keyboard, should be in automatic shifted. + loadKeyboard(ALPHABET_AUTOMATIC_SHIFTED); + // Update shift state, remained in automatic shifted. + updateShiftState(ALPHABET_AUTOMATIC_SHIFTED); + + // Press/release shift key, enter alphabet. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED); + // Press/release shift key, enter alphabet shifted. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + // Update shift state, enter to automatic shifted (not alphabet shifted). + updateShiftState(ALPHABET_AUTOMATIC_SHIFTED); + + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Update shift state, remained in alphabet shift locked (not automatic shifted). + updateShiftState(ALPHABET_SHIFT_LOCKED); + // Long press shift key, back to alphabet. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_UNSHIFTED); + + // Load keyboard, should be in automatic shifted. + loadKeyboard(ALPHABET_AUTOMATIC_SHIFTED); + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Update shift state, remained in symbols. + updateShiftState(SYMBOLS_UNSHIFTED); + + // Press/release "=\<" key, enter symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Update shift state, remained in symbols shifted. + updateShiftState(SYMBOLS_SHIFTED); + } + + // Sliding input in alphabet. + public void testSlidingAlphabet() { + // Alphabet -> shift key + letter -> alphabet. + // Press and slide from shift key, enter alphabet shifted. + pressAndSlideFromKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + // Enter/release letter key, switch back to alphabet. + pressAndReleaseKey('Z', ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED); + + // Alphabet -> "?123" key + letter -> alphabet. + // Press and slide from "123?" key, enter symbols. + pressAndSlideFromKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Enter/release into symbol letter key, switch back to alphabet. + pressAndReleaseKey('!', SYMBOLS_UNSHIFTED, ALPHABET_UNSHIFTED); + + // Alphabet shifted -> shift key + letter -> alphabet. + // Press/release shift key, enter alphabet shifted. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + // Press and slide from shift key, remain alphabet shifted. + pressAndSlideFromKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + // Enter/release letter key, switch back to alphabet (not alphabet shifted). + pressAndReleaseKey('Z', ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED); + + // Alphabet shifted -> "?123" key + letter -> alphabet. + // Press/release shift key, enter alphabet shifted. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + // Press and slide from "123?" key, enter symbols. + pressAndSlideFromKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Enter/release into symbol letter key, switch back to alphabet (not alphabet shifted). + pressAndReleaseKey('!', SYMBOLS_UNSHIFTED, ALPHABET_UNSHIFTED); + + // Alphabet shift locked -> shift key + letter -> alphabet shift locked. + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Press and slide from "123?" key, enter symbols. + pressAndSlideFromKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Enter/release into symbol letter key, switch back to alphabet shift locked. + pressAndReleaseKey('!', SYMBOLS_UNSHIFTED, ALPHABET_SHIFT_LOCKED); + + // Alphabet shift locked -> "?123" key + letter -> alphabet shift locked. + // Press and slide from shift key, enter alphabet shifted. + pressAndSlideFromKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Enter/release letter key, switch back to shift locked. + pressAndReleaseKey('Z', ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + } + + // Sliding input in symbols. + public void testSlidingSymbols() { + // Symbols -> "=\<" key + letter -> symbols. + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press and slide from shift key, enter symols shifted. + pressAndSlideFromKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Enter/release symbol shifted letter key, switch back to symbols. + pressAndReleaseKey('~', SYMBOLS_SHIFTED, SYMBOLS_UNSHIFTED); + + // Symbols -> "ABC" key + letter -> Symbols. + // Press and slide from "ABC" key, enter alphabet. + pressAndSlideFromKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + // Enter/release letter key, switch back to symbols. + pressAndReleaseKey('a', ALPHABET_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "ABC" key, switch to alphabet. + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + + // Alphabet shifted -> symbols -> "ABC" key + letter -> symbols -> + // alphabet. + // Load keyboard + loadKeyboard(ALPHABET_UNSHIFTED); + // Press/release shift key, enter alphabet shifted. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press and slide from "ABC" key. + pressAndSlideFromKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + // Enter/release letter key, switch back to symbols. + pressAndReleaseKey('a', ALPHABET_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "ABC" key, switch to alphabet (not alphabet shifted). + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + + // Alphabet shift locked -> symbols -> "ABC" key + letter -> symbols -> + // alphabet shift locked. + // Load keyboard + loadKeyboard(ALPHABET_UNSHIFTED); + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press and slide from "ABC" key, enter alphabet shift locked. + pressAndSlideFromKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + // Enter/release letter key, switch back to symbols. + pressAndReleaseKey('A', ALPHABET_SHIFT_LOCKED, SYMBOLS_UNSHIFTED); + // Press/release "ABC" key, switch to alphabet shift locked. + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + + // Alphabet shift locked -> symbols -> "=\<" key + letter -> symbols -> + // alphabet shift locked. + // Load keyboard + loadKeyboard(ALPHABET_UNSHIFTED); + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press and slide from "=\<" key, enter symbols shifted. + pressAndSlideFromKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Enter/release symbols shift letter key, switch back to symbols. + pressAndReleaseKey('~', SYMBOLS_SHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "ABC" key, switch to alphabet shift locked. + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + } + + // Sliding input in symbols shifted. + public void testSlidingSymbolsShifted() { + // Symbols shifted -> "?123" + letter -> symbols shifted. + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "=\<" key, enter into symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Press and slide from shift key, enter symbols. + pressAndSlideFromKey(CODE_SHIFT, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Enter/release symbol letter key, switch back to symbols shifted. + pressAndReleaseKey('1', SYMBOLS_UNSHIFTED, SYMBOLS_SHIFTED); + + // Symbols shifted -> "ABC" key + letter -> symbols shifted. + // Press and slide from "ABC" key, enter alphabet. + pressAndSlideFromKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + // Enter/release letter key, switch back to symbols shifted. + pressAndReleaseKey('a', ALPHABET_UNSHIFTED, SYMBOLS_SHIFTED); + // Press/release "ABC" key, switch to alphabet. + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + + // Alphabet shifted -> symbols shifted -> "ABC" + letter -> symbols shifted -> + // alphabet. + // Load keyboard + loadKeyboard(ALPHABET_UNSHIFTED); + // Press/release shift key, enter alphabet shifted. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "=\<" key, enter into symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Press and slide from "ABC" key. + pressAndSlideFromKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + // Enter/release letter key, switch back to symbols shifted. + pressAndReleaseKey('a', ALPHABET_UNSHIFTED, SYMBOLS_SHIFTED); + // Press/release "ABC" key, switch to alphabet (not alphabet shifted). + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + + // Alphabet shift locked -> symbols shifted -> "ABC" + letter -> symbols shifted -> + // alphabet shift locked. + // Load keyboard + loadKeyboard(ALPHABET_UNSHIFTED); + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "=\<" key, enter into symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Press and slide from "ABC" key. + pressAndSlideFromKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + // Enter/release letter key, switch back to symbols shifted. + pressAndReleaseKey('A', ALPHABET_SHIFT_LOCKED, SYMBOLS_SHIFTED); + // Press/release "ABC" key, switch to alphabet shift locked. + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + + // Alphabet shift locked -> symbols shifted -> "?123" + letter -> symbols shifted -> + // alphabet shift locked. + // Load keyboard + loadKeyboard(ALPHABET_UNSHIFTED); + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Press/release "?123" key, enter into symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "=\<" key, enter into symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Press and slide from "?123" key. + pressAndSlideFromKey(CODE_SHIFT, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Enter/release symbol letter key, switch back to symbols shifted. + pressAndReleaseKey('1', SYMBOLS_UNSHIFTED, SYMBOLS_SHIFTED); + // Press/release "ABC" key, switch to alphabet shift locked. + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + } + + // Change focus to new text field. + public void testChangeFocus() { + // Press/release shift key. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + // Change focus to new text field. + loadKeyboard(ALPHABET_UNSHIFTED); + + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Change focus to new text field. + loadKeyboard(ALPHABET_UNSHIFTED); + + // Press/release "?123" key. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Change focus to new text field. + loadKeyboard(ALPHABET_UNSHIFTED); + + // Press/release "?123" key. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "=\<" key. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Change focus to new text field. + loadKeyboard(ALPHABET_UNSHIFTED); + } + + // Change focus to auto caps text field. + public void testChangeFocusAutoCaps() { + // Set auto caps mode on. + setAutoCapsMode(AUTO_CAPS); + + // Update shift state. + updateShiftState(ALPHABET_AUTOMATIC_SHIFTED); + // Change focus to new text field. + loadKeyboard(ALPHABET_AUTOMATIC_SHIFTED); + + // Press/release shift key, enter alphabet. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED); + // Change focus to new text field. + loadKeyboard(ALPHABET_AUTOMATIC_SHIFTED); + + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Change focus to new text field. + loadKeyboard(ALPHABET_AUTOMATIC_SHIFTED); + + // Press/release "?123" key. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Change focus to new text field. + loadKeyboard(ALPHABET_AUTOMATIC_SHIFTED); + + // Press/release "?123" key. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "=\<" key. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Change focus to new text field. + loadKeyboard(ALPHABET_AUTOMATIC_SHIFTED); + } + + // Change orientation. + public void testChangeOrientation() { + // Alphabet -> rotate -> alphabet. + updateShiftState(ALPHABET_UNSHIFTED); + // Rotate device, remain in alphabet. + rotateDevice(ALPHABET_UNSHIFTED); + + // Alphabet shifted -> rotate -> alphabet shifted. + // Press/release shift key, enter alphabet shifted. + pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED); + // Rotate device, remain in alphabet shifted. + rotateDevice(ALPHABET_MANUAL_SHIFTED); + + // Alphabet shift locked -> rotate -> alphabet shift locked. + // Long press shift key, enter alphabet shift locked. + longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED); + // Rotate device, remain in alphabet shift locked. + rotateDevice(ALPHABET_SHIFT_LOCKED); + + // Alphabet shift locked -> symbols -> rotate -> symbols -> + // Alphabet shift locked. + // Press/release "?123" key, enter symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Rotate device, remain in symbols, + rotateDevice(SYMBOLS_UNSHIFTED); + // Press/release "ABC" key, alphabet shift locked state should be maintained. + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + + // Alphabet shift locked -> symbols shifted -> rotate -> symbols shifted -> + // Alphabet shift locked. + // Press/release "?123" key, enter symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "=\<" key, enter symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Rotate device, remain in symbols shifted. + rotateDevice(SYMBOLS_SHIFTED); + // Press/release "ABC" key, alphabet shift locked state should be maintained. + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + + // Alphabet shift locked -> symbols shifted -> alphabet shift locked -> rotate -> + // Alphabet shift locked -> symbols. + // Press/release "?123" key, enter symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "=\<" key, enter symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Press/release "ABC" key, enter alphabet shift locked. + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED); + // Rotate device, remain in alphabet shift locked. + rotateDevice(ALPHABET_SHIFT_LOCKED); + // Press/release "?123" key, enter symbols (not symbols shifted). + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + + // Alphabet -> symbols shifted -> alphabet -> rotate -> + // Alphabet -> symbols. + loadKeyboard(ALPHABET_UNSHIFTED); + // Press/release "?123" key, enter symbols. + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + // Press/release "=\<" key, enter symbols shifted. + pressAndReleaseKey(CODE_SHIFT, SYMBOLS_SHIFTED, SYMBOLS_SHIFTED); + // Press/release "ABC" key, enter alphabet. + pressAndReleaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED); + // Rotate device, remain in alphabet shift locked. + rotateDevice(ALPHABET_UNSHIFTED); + // Press/release "?123" key, enter symbols (not symbols shifted). + pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java new file mode 100644 index 000000000..96a54668c --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2012 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; + +import android.test.AndroidTestCase; + +public class KeyboardStateTestsBase extends AndroidTestCase + implements MockKeyboardSwitcher.Constants { + protected MockKeyboardSwitcher mSwitcher; + + private String mLayoutSwitchBackSymbols = ""; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mSwitcher = new MockKeyboardSwitcher(); + mSwitcher.setAutoCapsMode(NO_AUTO_CAPS); + + loadKeyboard(ALPHABET_UNSHIFTED); + } + + public void setAutoCapsMode(boolean autoCaps) { + mSwitcher.setAutoCapsMode(autoCaps); + } + + public void setLayoutSwitchBackSymbols(String switchBackSymbols) { + mLayoutSwitchBackSymbols = switchBackSymbols; + } + + private static void assertLayout(int expected, int actual) { + assertTrue("expected=" + MockKeyboardSwitcher.getLayoutName(expected) + + " actual=" + MockKeyboardSwitcher.getLayoutName(actual), + expected == actual); + } + + public void updateShiftState(int afterUpdate) { + mSwitcher.updateShiftState(); + assertLayout(afterUpdate, mSwitcher.getLayoutId()); + } + + public void loadKeyboard(int afterLoad) { + mSwitcher.loadKeyboard(mLayoutSwitchBackSymbols); + updateShiftState(afterLoad); + } + + public void rotateDevice(int afterRotate) { + mSwitcher.saveKeyboardState(); + mSwitcher.loadKeyboard(mLayoutSwitchBackSymbols); + assertLayout(afterRotate, mSwitcher.getLayoutId()); + } + + private void pressKeyWithoutTimerExpire(int code, int afterPress) { + mSwitcher.onPressKey(code); + assertLayout(afterPress, mSwitcher.getLayoutId()); + } + + public void pressKey(int code, int afterPress) { + mSwitcher.expireDoubleTapTimeout(); + pressKeyWithoutTimerExpire(code, afterPress); + } + + public void releaseKey(int code, int afterRelease) { + mSwitcher.onCodeInput(code, SINGLE); + mSwitcher.onReleaseKey(code, NOT_SLIDING); + assertLayout(afterRelease, mSwitcher.getLayoutId()); + } + + public void pressAndReleaseKey(int code, int afterPress, int afterRelease) { + pressKey(code, afterPress); + releaseKey(code, afterRelease); + } + + public void chordingPressKey(int code, int afterPress) { + pressKey(code, afterPress); + } + + public void chordingReleaseKey(int code, int afterRelease) { + mSwitcher.onCodeInput(code, MULTI); + mSwitcher.onReleaseKey(code, NOT_SLIDING); + assertLayout(afterRelease, mSwitcher.getLayoutId()); + } + + public void chordingPressAndReleaseKey(int code, int afterPress, int afterRelease) { + chordingPressKey(code, afterPress); + chordingReleaseKey(code, afterRelease); + } + + public void pressAndSlideFromKey(int code, int afterPress, int afterSlide) { + pressKey(code, afterPress); + mSwitcher.onReleaseKey(code, SLIDING); + assertLayout(afterSlide, mSwitcher.getLayoutId()); + } + + public void longPressAndReleaseKey(int code, int afterPress, int afterLongPress) { + pressKey(code, afterPress); + mSwitcher.onLongPressTimeout(code); + assertLayout(afterLongPress, mSwitcher.getLayoutId()); + releaseKey(code, afterLongPress); + } + + public void secondPressAndReleaseKey(int code, int afterPress, int afterRelease) { + pressKeyWithoutTimerExpire(code, afterPress); + releaseKey(code, afterRelease); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java new file mode 100644 index 000000000..a01b69cc1 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2012 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; + +import com.android.inputmethod.keyboard.Keyboard; + +public class MockKeyboardSwitcher implements KeyboardState.SwitchActions { + public interface Constants { + // Argument for {@link KeyboardState#onPressKey} and {@link KeyboardState#onReleaseKey}. + public static final boolean NOT_SLIDING = false; + public static final boolean SLIDING = true; + // Argument for {@link KeyboardState#onCodeInput}. + public static final boolean SINGLE = true; + public static final boolean MULTI = false; + public static final boolean NO_AUTO_CAPS = false; + public static final boolean AUTO_CAPS = true; + + public static final int CODE_SHIFT = Keyboard.CODE_SHIFT; + public static final int CODE_SYMBOL = Keyboard.CODE_SWITCH_ALPHA_SYMBOL; + public static final int CODE_SPACE = Keyboard.CODE_SPACE; + public static final int CODE_AUTO_CAPS_TRIGGER = Keyboard.CODE_SPACE; + + public static final int ALPHABET_UNSHIFTED = 0; + public static final int ALPHABET_MANUAL_SHIFTED = 1; + public static final int ALPHABET_AUTOMATIC_SHIFTED = 2; + public static final int ALPHABET_SHIFT_LOCKED = 3; + public static final int ALPHABET_SHIFT_LOCK_SHIFTED = 4; + public static final int SYMBOLS_UNSHIFTED = 5; + public static final int SYMBOLS_SHIFTED = 6; + } + + private int mLayout = Constants.ALPHABET_UNSHIFTED; + + private boolean mAutoCapsMode = Constants.NO_AUTO_CAPS; + // Following InputConnection's behavior. Simulating InputType.TYPE_TEXT_FLAG_CAP_WORDS. + private boolean mAutoCapsState = true; + + private boolean mIsInDoubleTapTimeout; + private int mLongPressTimeoutCode; + + private final KeyboardState mState = new KeyboardState(this); + + public int getLayoutId() { + return mLayout; + } + + public static String getLayoutName(int layoutId) { + switch (layoutId) { + case Constants.ALPHABET_UNSHIFTED: return "ALPHABET_UNSHIFTED"; + case Constants.ALPHABET_MANUAL_SHIFTED: return "ALPHABET_MANUAL_SHIFTED"; + case Constants.ALPHABET_AUTOMATIC_SHIFTED: return "ALPHABET_AUTOMATIC_SHIFTED"; + case Constants.ALPHABET_SHIFT_LOCKED: return "ALPHABET_SHIFT_LOCKED"; + case Constants.ALPHABET_SHIFT_LOCK_SHIFTED: return "ALPHABET_SHIFT_LOCK_SHIFTED"; + case Constants.SYMBOLS_UNSHIFTED: return "SYMBOLS_UNSHIFTED"; + case Constants.SYMBOLS_SHIFTED: return "SYMBOLS_SHIFTED"; + default: return "UNKNOWN<" + layoutId + ">"; + } + } + + public void setAutoCapsMode(boolean autoCaps) { + mAutoCapsMode = autoCaps; + } + + public void expireDoubleTapTimeout() { + mIsInDoubleTapTimeout = false; + } + + @Override + public void setAlphabetKeyboard() { + mLayout = Constants.ALPHABET_UNSHIFTED; + } + + @Override + public void setAlphabetManualShiftedKeyboard() { + mLayout = Constants.ALPHABET_MANUAL_SHIFTED; + } + + @Override + public void setAlphabetAutomaticShiftedKeyboard() { + mLayout = Constants.ALPHABET_AUTOMATIC_SHIFTED; + } + + @Override + public void setAlphabetShiftLockedKeyboard() { + mLayout = Constants.ALPHABET_SHIFT_LOCKED; + } + + @Override + public void setAlphabetShiftLockShiftedKeyboard() { + mLayout = Constants.ALPHABET_SHIFT_LOCK_SHIFTED; + } + + @Override + public void setSymbolsKeyboard() { + mLayout = Constants.SYMBOLS_UNSHIFTED; + } + + @Override + public void setSymbolsShiftedKeyboard() { + mLayout = Constants.SYMBOLS_SHIFTED; + } + + @Override + public void requestUpdatingShiftState() { + mState.onUpdateShiftState(mAutoCapsMode && mAutoCapsState); + } + + @Override + public void startDoubleTapTimer() { + mIsInDoubleTapTimeout = true; + } + + @Override + public boolean isInDoubleTapTimeout() { + return mIsInDoubleTapTimeout; + } + + @Override + public void startLongPressTimer(int code) { + mLongPressTimeoutCode = code; + } + + @Override + public void hapticAndAudioFeedback(int code) { + // Nothing to do. + } + + public void onLongPressTimeout(int code) { + // TODO: Handle simultaneous long presses. + if (mLongPressTimeoutCode == code) { + mLongPressTimeoutCode = 0; + mState.onLongPressTimeout(code); + } + } + + public void updateShiftState() { + mState.onUpdateShiftState(mAutoCapsMode && mAutoCapsState); + } + + public void loadKeyboard(String layoutSwitchBackSymbols) { + mState.onLoadKeyboard(layoutSwitchBackSymbols); + } + + public void saveKeyboardState() { + mState.onSaveKeyboardState(); + } + + public void onPressKey(int code) { + mState.onPressKey(code); + } + + public void onReleaseKey(int code, boolean withSliding) { + mState.onReleaseKey(code, withSliding); + if (mLongPressTimeoutCode == code) { + mLongPressTimeoutCode = 0; + } + } + + public void onCodeInput(int code, boolean isSinglePointer) { + if (Keyboard.isLetterCode(code)) { + mAutoCapsState = (code == Constants.CODE_AUTO_CAPS_TRIGGER); + } + mState.onCodeInput(code, isSinglePointer, mAutoCapsMode && mAutoCapsState); + } + + public void onCancelInput(boolean isSinglePointer) { + mState.onCancelInput(isSinglePointer); + } +}
\ No newline at end of file diff --git a/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecParserTests.java b/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecParserTests.java deleted file mode 100644 index 798fca0f5..000000000 --- a/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecParserTests.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.keyboard.internal; - -import android.content.res.Resources; -import android.test.AndroidTestCase; - -import com.android.inputmethod.keyboard.Keyboard; -import com.android.inputmethod.latin.R; - -public class MoreKeySpecParserTests extends AndroidTestCase { - private Resources mRes; - - private static final int ICON_SETTINGS_KEY = 5; - private static final int ICON_UNDEFINED = KeyboardIconsSet.ICON_UNDEFINED; - - private static final String CODE_SETTINGS = "@integer/key_settings"; - private static final String ICON_SETTINGS = "@icon/" + ICON_SETTINGS_KEY; - private static final String CODE_NON_EXISTING = "@integer/non_existing"; - private static final String ICON_NON_EXISTING = "@icon/non_existing"; - - private int mCodeSettings; - - @Override - protected void setUp() { - Resources res = getContext().getResources(); - mRes = res; - - final String packageName = res.getResourcePackageName(R.string.english_ime_name); - final int codeId = res.getIdentifier(CODE_SETTINGS.substring(1), null, packageName); - mCodeSettings = res.getInteger(codeId); - } - - private void assertParser(String message, String moreKeySpec, String expectedLabel, - String expectedOutputText, int expectedIcon, int expectedCode) { - String actualLabel = MoreKeySpecParser.getLabel(moreKeySpec); - assertEquals(message + ": label:", expectedLabel, actualLabel); - - String actualOutputText = MoreKeySpecParser.getOutputText(moreKeySpec); - assertEquals(message + ": ouptputText:", expectedOutputText, actualOutputText); - - int actualIcon = MoreKeySpecParser.getIconId(moreKeySpec); - assertEquals(message + ": icon:", expectedIcon, actualIcon); - - int actualCode = MoreKeySpecParser.getCode(mRes, moreKeySpec); - assertEquals(message + ": codes value:", expectedCode, actualCode); - } - - private void assertParserError(String message, String moreKeySpec, String expectedLabel, - String expectedOutputText, int expectedIcon, int expectedCode) { - try { - assertParser(message, moreKeySpec, expectedLabel, expectedOutputText, expectedIcon, - expectedCode); - fail(message); - } catch (MoreKeySpecParser.MoreKeySpecParserError pcpe) { - // success. - } - } - - public void testSingleLetter() { - assertParser("Single letter", "a", - "a", null, ICON_UNDEFINED, 'a'); - assertParser("Single escaped bar", "\\|", - "|", null, ICON_UNDEFINED, '|'); - assertParser("Single escaped escape", "\\\\", - "\\", null, ICON_UNDEFINED, '\\'); - assertParser("Single comma", ",", - ",", null, ICON_UNDEFINED, ','); - assertParser("Single escaped comma", "\\,", - ",", null, ICON_UNDEFINED, ','); - assertParser("Single escaped letter", "\\a", - "a", null, ICON_UNDEFINED, 'a'); - assertParser("Single at", "@", - "@", null, ICON_UNDEFINED, '@'); - assertParser("Single escaped at", "\\@", - "@", null, ICON_UNDEFINED, '@'); - assertParser("Single letter with outputText", "a|abc", - "a", "abc", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Single letter with escaped outputText", "a|a\\|c", - "a", "a|c", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Single letter with comma outputText", "a|a,b", - "a", "a,b", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Single letter with escaped comma outputText", "a|a\\,b", - "a", "a,b", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Single letter with outputText starts with at", "a|@bc", - "a", "@bc", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Single letter with outputText contains at", "a|a@c", - "a", "a@c", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Single letter with escaped at outputText", "a|\\@bc", - "a", "@bc", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Single escaped escape with outputText", "\\\\|\\\\", - "\\", "\\", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Single escaped bar with outputText", "\\||\\|", - "|", "|", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Single letter with code", "a|" + CODE_SETTINGS, - "a", null, ICON_UNDEFINED, mCodeSettings); - } - - public void testLabel() { - assertParser("Simple label", "abc", - "abc", "abc", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label with escaped bar", "a\\|c", - "a|c", "a|c", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label with escaped escape", "a\\\\c", - "a\\c", "a\\c", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label with comma", "a,c", - "a,c", "a,c", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label with escaped comma", "a\\,c", - "a,c", "a,c", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label starts with at", "@bc", - "@bc", "@bc", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label contains at", "a@c", - "a@c", "a@c", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label with escaped at", "\\@bc", - "@bc", "@bc", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label with escaped letter", "\\abc", - "abc", "abc", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label with outputText", "abc|def", - "abc", "def", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label with comma and outputText", "a,c|def", - "a,c", "def", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Escaped comma label with outputText", "a\\,c|def", - "a,c", "def", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Escaped label with outputText", "a\\|c|def", - "a|c", "def", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label with escaped bar outputText", "abc|d\\|f", - "abc", "d|f", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Escaped escape label with outputText", "a\\\\|def", - "a\\", "def", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label starts with at and outputText", "@bc|def", - "@bc", "def", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label contains at label and outputText", "a@c|def", - "a@c", "def", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Escaped at label with outputText", "\\@bc|def", - "@bc", "def", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label with comma outputText", "abc|a,b", - "abc", "a,b", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label with escaped comma outputText", "abc|a\\,b", - "abc", "a,b", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label with outputText starts with at", "abc|@bc", - "abc", "@bc", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label with outputText contains at", "abc|a@c", - "abc", "a@c", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label with escaped at outputText", "abc|\\@bc", - "abc", "@bc", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label with escaped bar outputText", "abc|d\\|f", - "abc", "d|f", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Escaped bar label with escaped bar outputText", "a\\|c|d\\|f", - "a|c", "d|f", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParser("Label with code", "abc|" + CODE_SETTINGS, - "abc", null, ICON_UNDEFINED, mCodeSettings); - assertParser("Escaped label with code", "a\\|c|" + CODE_SETTINGS, - "a|c", null, ICON_UNDEFINED, mCodeSettings); - } - - public void testIconAndCode() { - assertParser("Icon with outputText", ICON_SETTINGS + "|abc", - null, "abc", ICON_SETTINGS_KEY, Keyboard.CODE_DUMMY); - assertParser("Icon with outputText starts with at", ICON_SETTINGS + "|@bc", - null, "@bc", ICON_SETTINGS_KEY, Keyboard.CODE_DUMMY); - assertParser("Icon with outputText contains at", ICON_SETTINGS + "|a@c", - null, "a@c", ICON_SETTINGS_KEY, Keyboard.CODE_DUMMY); - assertParser("Icon with escaped at outputText", ICON_SETTINGS + "|\\@bc", - null, "@bc", ICON_SETTINGS_KEY, Keyboard.CODE_DUMMY); - assertParser("Label starts with at and code", "@bc|" + CODE_SETTINGS, - "@bc", null, ICON_UNDEFINED, mCodeSettings); - assertParser("Label contains at and code", "a@c|" + CODE_SETTINGS, - "a@c", null, ICON_UNDEFINED, mCodeSettings); - assertParser("Escaped at label with code", "\\@bc|" + CODE_SETTINGS, - "@bc", null, ICON_UNDEFINED, mCodeSettings); - assertParser("Icon with code", ICON_SETTINGS + "|" + CODE_SETTINGS, - null, null, ICON_SETTINGS_KEY, mCodeSettings); - } - - public void testFormatError() { - assertParserError("Empty spec", "", null, - null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); - assertParserError("Empty label with outputText", "|a", - null, "a", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParserError("Empty label with code", "|" + CODE_SETTINGS, - null, null, ICON_UNDEFINED, mCodeSettings); - assertParserError("Empty outputText with label", "a|", - "a", null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); - assertParserError("Empty outputText with icon", ICON_SETTINGS + "|", - null, null, ICON_SETTINGS_KEY, Keyboard.CODE_UNSPECIFIED); - assertParserError("Empty icon and code", "|", - null, null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); - assertParserError("Icon without code", ICON_SETTINGS, - null, null, ICON_SETTINGS_KEY, Keyboard.CODE_DUMMY); - assertParser("Non existing icon", ICON_NON_EXISTING + "|abc", - null, "abc", ICON_UNDEFINED, Keyboard.CODE_DUMMY); - assertParserError("Non existing code", "abc|" + CODE_NON_EXISTING, - "abc", null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); - assertParserError("Third bar at end", "a|b|", - "a", null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); - assertParserError("Multiple bar", "a|b|c", - "a", null, ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED); - assertParserError("Multiple bar with label and code", "a|" + CODE_SETTINGS + "|c", - "a", null, ICON_UNDEFINED, mCodeSettings); - assertParserError("Multiple bar with icon and outputText", ICON_SETTINGS + "|b|c", - null, null, ICON_SETTINGS_KEY, Keyboard.CODE_UNSPECIFIED); - assertParserError("Multiple bar with icon and code", - ICON_SETTINGS + "|" + CODE_SETTINGS + "|c", - null, null, ICON_SETTINGS_KEY, mCodeSettings); - } -} diff --git a/tests/src/com/android/inputmethod/latin/EditDistanceTests.java b/tests/src/com/android/inputmethod/latin/EditDistanceTests.java index 75bd04938..c053a49e5 100644 --- a/tests/src/com/android/inputmethod/latin/EditDistanceTests.java +++ b/tests/src/com/android/inputmethod/latin/EditDistanceTests.java @@ -37,7 +37,7 @@ public class EditDistanceTests extends AndroidTestCase { * sitting */ public void testExample1() { - final int dist = Utils.editDistance("kitten", "sitting"); + final int dist = BinaryDictionary.editDistance("kitten", "sitting"); assertEquals("edit distance between 'kitten' and 'sitting' is 3", 3, dist); } @@ -50,26 +50,26 @@ public class EditDistanceTests extends AndroidTestCase { * S--unday */ public void testExample2() { - final int dist = Utils.editDistance("Saturday", "Sunday"); + final int dist = BinaryDictionary.editDistance("Saturday", "Sunday"); assertEquals("edit distance between 'Saturday' and 'Sunday' is 3", 3, dist); } public void testBothEmpty() { - final int dist = Utils.editDistance("", ""); + final int dist = BinaryDictionary.editDistance("", ""); assertEquals("when both string are empty, no edits are needed", 0, dist); } public void testFirstArgIsEmpty() { - final int dist = Utils.editDistance("", "aaaa"); + final int dist = BinaryDictionary.editDistance("", "aaaa"); assertEquals("when only one string of the arguments is empty," + " the edit distance is the length of the other.", 4, dist); } public void testSecoondArgIsEmpty() { - final int dist = Utils.editDistance("aaaa", ""); + final int dist = BinaryDictionary.editDistance("aaaa", ""); assertEquals("when only one string of the arguments is empty," + " the edit distance is the length of the other.", 4, dist); @@ -78,27 +78,27 @@ public class EditDistanceTests extends AndroidTestCase { public void testSameStrings() { final String arg1 = "The quick brown fox jumps over the lazy dog."; final String arg2 = "The quick brown fox jumps over the lazy dog."; - final int dist = Utils.editDistance(arg1, arg2); + final int dist = BinaryDictionary.editDistance(arg1, arg2); assertEquals("when same strings are passed, distance equals 0.", 0, dist); } public void testSameReference() { final String arg = "The quick brown fox jumps over the lazy dog."; - final int dist = Utils.editDistance(arg, arg); + final int dist = BinaryDictionary.editDistance(arg, arg); assertEquals("when same string references are passed, the distance equals 0.", 0, dist); } public void testNullArg() { try { - Utils.editDistance(null, "aaa"); + BinaryDictionary.editDistance(null, "aaa"); fail("IllegalArgumentException should be thrown."); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { - Utils.editDistance("aaa", null); + BinaryDictionary.editDistance("aaa", null); fail("IllegalArgumentException should be thrown."); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java new file mode 100644 index 000000000..9d886da3b --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java @@ -0,0 +1,399 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.test.ServiceTestCase; +import android.text.InputType; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.view.View; +import android.view.inputmethod.BaseInputConnection; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputConnection; +import android.widget.FrameLayout; +import android.widget.TextView; + +import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.KeyboardActionListener; +import com.android.inputmethod.latin.spellcheck.AndroidSpellCheckerService; // for proximity info +import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo; + +import java.util.Arrays; +import java.util.HashMap; + +public class InputLogicTests extends ServiceTestCase<LatinIME> { + + private static final String PREF_DEBUG_MODE = "debug_mode"; + + private LatinIME mLatinIME; + private TextView mTextView; + private InputConnection mInputConnection; + private HashMap<Integer, int[]> mProximity; + + public InputLogicTests() { + super(LatinIME.class); + mProximity = createProximity(); + } + + private static HashMap<Integer, int[]> createProximity() { + final HashMap<Integer, int[]> proximity = new HashMap<Integer, int[]>(); + final int[] testProximity = SpellCheckerProximityInfo.getProximityForScript( + AndroidSpellCheckerService.SCRIPT_LATIN); + final int ROW_SIZE = SpellCheckerProximityInfo.ROW_SIZE; + final int NUL = SpellCheckerProximityInfo.NUL; + for (int row = 0; row * ROW_SIZE < testProximity.length; ++row) { + final int rowBase = row * ROW_SIZE; + int column; + for (column = 1; NUL != testProximity[rowBase + column]; ++column) { + // Do nothing, just search for a NUL element + } + proximity.put(testProximity[row * ROW_SIZE], + Arrays.copyOfRange(testProximity, rowBase, rowBase + column)); + } + return proximity; + } + + // returns the previous setting value + private boolean setDebugMode(final boolean mode) { + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mLatinIME); + final boolean previousDebugSetting = prefs.getBoolean(PREF_DEBUG_MODE, false); + final SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean(PREF_DEBUG_MODE, true); + editor.commit(); + return previousDebugSetting; + } + + @Override + protected void setUp() { + try { + super.setUp(); + } catch (Exception e) { + e.printStackTrace(); + } + mTextView = new TextView(getContext()); + mTextView.setInputType(InputType.TYPE_CLASS_TEXT); + mTextView.setEnabled(true); + setupService(); + mLatinIME = getService(); + final boolean previousDebugSetting = setDebugMode(true); + mLatinIME.onCreate(); + setDebugMode(previousDebugSetting); + final EditorInfo ei = new EditorInfo(); + ei.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT; + final InputConnection ic = mTextView.onCreateInputConnection(ei); + ei.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT; + final LayoutInflater inflater = + (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + final ViewGroup vg = new FrameLayout(getContext()); + final View inputView = inflater.inflate(R.layout.input_view, vg); + mLatinIME.setInputView(inputView); + mLatinIME.onBindInput(); + mLatinIME.onCreateInputView(); + mLatinIME.onStartInputView(ei, false); + mLatinIME.onCreateInputMethodInterface().startInput(ic, ei); + mInputConnection = ic; + // Wait for the main dictionary to be loaded (we need it for auto-correction tests) + int remainingAttempts = 10; + while (remainingAttempts > 0 && !mLatinIME.mSuggest.hasMainDictionary()) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // Don't do much + } finally { + --remainingAttempts; + } + } + if (!mLatinIME.mSuggest.hasMainDictionary()) { + throw new RuntimeException("Can't initialize the main dictionary"); + } + } + + // type(int) and type(String): helper methods to send a code point resp. a string to LatinIME. + private void type(final int codePoint) { + // onPressKey and onReleaseKey are explicitly deactivated here, but they do happen in the + // code (although multitouch/slide input and other factors make the sequencing complicated). + // They are supposed to be entirely deconnected from the input logic from LatinIME point of + // view and only delegates to the parts of the code that care. So we don't include them here + // to keep these tests as pinpoint as possible and avoid bringing it too many dependencies, + // but keep them in mind if something breaks. Commenting them out as is should work. + //mLatinIME.onPressKey(codePoint); + int[] proximityKeys = mProximity.get(codePoint); + if (null == proximityKeys) { + proximityKeys = new int[] { codePoint }; + } + mLatinIME.onCodeInput(codePoint, proximityKeys, + KeyboardActionListener.NOT_A_TOUCH_COORDINATE, + KeyboardActionListener.NOT_A_TOUCH_COORDINATE); + //mLatinIME.onReleaseKey(codePoint, false); + } + + private void type(final String stringToType) { + for (int i = 0; i < stringToType.length(); i = stringToType.offsetByCodePoints(i, 1)) { + type(stringToType.codePointAt(i)); + } + } + + public void testTypeWord() { + final String WORD_TO_TYPE = "abcd"; + type(WORD_TO_TYPE); + assertEquals("type word", WORD_TO_TYPE, mTextView.getText().toString()); + } + + public void testPickSuggestionThenBackspace() { + final String WORD_TO_TYPE = "this"; + final String EXPECTED_RESULT = "this"; + type(WORD_TO_TYPE); + mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE); + mLatinIME.onUpdateSelection(0, 0, WORD_TO_TYPE.length(), WORD_TO_TYPE.length(), -1, -1); + type(Keyboard.CODE_DELETE); + assertEquals("press suggestion then backspace", EXPECTED_RESULT, + mTextView.getText().toString()); + } + + public void testPickTypedWordOverAutoCorrectionThenBackspace() { + final String WORD_TO_TYPE = "tgis"; + final String EXPECTED_RESULT = "tgis"; + type(WORD_TO_TYPE); + // Choose the typed word, which should be in position 1 (because position 0 should + // be occupied by the "this" auto-correction, as checked by testAutoCorrect()) + mLatinIME.pickSuggestionManually(1, WORD_TO_TYPE); + mLatinIME.onUpdateSelection(0, 0, WORD_TO_TYPE.length(), WORD_TO_TYPE.length(), -1, -1); + type(Keyboard.CODE_DELETE); + assertEquals("pick typed word over auto-correction then backspace", EXPECTED_RESULT, + mTextView.getText().toString()); + } + + public void testDeleteSelection() { + final String STRING_TO_TYPE = "some text delete me some text"; + final int SELECTION_START = 10; + final int SELECTION_END = 19; + final String EXPECTED_RESULT = "some text some text"; + type(STRING_TO_TYPE); + // There is no IMF to call onUpdateSelection for us so we must do it by hand. + // Send once to simulate the cursor actually responding to the move caused by typing. + // This is necessary because LatinIME is bookkeeping to avoid confusing a real cursor + // move with a move triggered by LatinIME inputting stuff. + mLatinIME.onUpdateSelection(0, 0, STRING_TO_TYPE.length(), STRING_TO_TYPE.length(), -1, -1); + mInputConnection.setSelection(SELECTION_START, SELECTION_END); + // And now we simulate the user actually selecting some text. + mLatinIME.onUpdateSelection(0, 0, SELECTION_START, SELECTION_END, -1, -1); + type(Keyboard.CODE_DELETE); + assertEquals("delete selection", EXPECTED_RESULT, mTextView.getText().toString()); + } + + public void testAutoCorrect() { + final String STRING_TO_TYPE = "tgis "; + final String EXPECTED_RESULT = "this "; + type(STRING_TO_TYPE); + assertEquals("simple auto-correct", EXPECTED_RESULT, mTextView.getText().toString()); + } + + public void testDoubleSpace() { + final String STRING_TO_TYPE = "this "; + final String EXPECTED_RESULT = "this. "; + type(STRING_TO_TYPE); + assertEquals("double space make a period", EXPECTED_RESULT, mTextView.getText().toString()); + } + + public void testCancelDoubleSpace() { + final String STRING_TO_TYPE = "this "; + final String EXPECTED_RESULT = "this "; + type(STRING_TO_TYPE); + type(Keyboard.CODE_DELETE); + assertEquals("double space make a period", EXPECTED_RESULT, mTextView.getText().toString()); + } + + public void testBackspaceAtStartAfterAutocorrect() { + final String STRING_TO_TYPE = "tgis "; + final String EXPECTED_RESULT = "this "; + final int NEW_CURSOR_POSITION = 0; + type(STRING_TO_TYPE); + mLatinIME.onUpdateSelection(0, 0, STRING_TO_TYPE.length(), STRING_TO_TYPE.length(), -1, -1); + mInputConnection.setSelection(NEW_CURSOR_POSITION, NEW_CURSOR_POSITION); + mLatinIME.onUpdateSelection(0, 0, NEW_CURSOR_POSITION, NEW_CURSOR_POSITION, -1, -1); + type(Keyboard.CODE_DELETE); + assertEquals("auto correct then move cursor to start of line then backspace", + EXPECTED_RESULT, mTextView.getText().toString()); + } + + public void testAutoCorrectThenMoveCursorThenBackspace() { + final String STRING_TO_TYPE = "and tgis "; + final String EXPECTED_RESULT = "andthis "; + final int NEW_CURSOR_POSITION = STRING_TO_TYPE.indexOf('t'); + type(STRING_TO_TYPE); + mLatinIME.onUpdateSelection(0, 0, STRING_TO_TYPE.length(), STRING_TO_TYPE.length(), -1, -1); + mInputConnection.setSelection(NEW_CURSOR_POSITION, NEW_CURSOR_POSITION); + mLatinIME.onUpdateSelection(0, 0, NEW_CURSOR_POSITION, NEW_CURSOR_POSITION, -1, -1); + type(Keyboard.CODE_DELETE); + assertEquals("auto correct then move cursor then backspace", + EXPECTED_RESULT, mTextView.getText().toString()); + } + + public void testNoSpaceAfterManualPick() { + final String WORD_TO_TYPE = "this"; + final String EXPECTED_RESULT = WORD_TO_TYPE; + type(WORD_TO_TYPE); + mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE); + assertEquals("no space after manual pick", EXPECTED_RESULT, + mTextView.getText().toString()); + } + + public void testManualPickThenType() { + final String WORD1_TO_TYPE = "this"; + final String WORD2_TO_TYPE = "is"; + final String EXPECTED_RESULT = "this is"; + type(WORD1_TO_TYPE); + mLatinIME.pickSuggestionManually(0, WORD1_TO_TYPE); + type(WORD2_TO_TYPE); + assertEquals("manual pick then type", EXPECTED_RESULT, mTextView.getText().toString()); + } + + public void testManualPickThenSeparator() { + final String WORD1_TO_TYPE = "this"; + final String WORD2_TO_TYPE = "!"; + final String EXPECTED_RESULT = "this!"; + type(WORD1_TO_TYPE); + mLatinIME.pickSuggestionManually(0, WORD1_TO_TYPE); + type(WORD2_TO_TYPE); + assertEquals("manual pick then separator", EXPECTED_RESULT, mTextView.getText().toString()); + } + + public void testWordThenSpaceThenPunctuationFromStripTwice() { + final String WORD_TO_TYPE = "this "; + final String PUNCTUATION_FROM_STRIP = "!"; + final String EXPECTED_RESULT = "this!! "; + type(WORD_TO_TYPE); + mLatinIME.pickSuggestionManually(0, PUNCTUATION_FROM_STRIP); + mLatinIME.pickSuggestionManually(0, PUNCTUATION_FROM_STRIP); + assertEquals("type word then type space then punctuation from strip twice", EXPECTED_RESULT, + mTextView.getText().toString()); + } + + public void testWordThenSpaceThenPunctuationFromKeyboardTwice() { + final String WORD_TO_TYPE = "this !!"; + final String EXPECTED_RESULT = "this !!"; + type(WORD_TO_TYPE); + assertEquals("manual pick then space then punctuation from keyboard twice", EXPECTED_RESULT, + mTextView.getText().toString()); + } + + public void testManualPickThenPunctuationFromStripTwiceThenType() { + final String WORD1_TO_TYPE = "this"; + final String WORD2_TO_TYPE = "is"; + final String PUNCTUATION_FROM_STRIP = "!"; + final String EXPECTED_RESULT = "this!! is"; + type(WORD1_TO_TYPE); + mLatinIME.pickSuggestionManually(0, WORD1_TO_TYPE); + mLatinIME.pickSuggestionManually(0, PUNCTUATION_FROM_STRIP); + mLatinIME.pickSuggestionManually(0, PUNCTUATION_FROM_STRIP); + type(WORD2_TO_TYPE); + assertEquals("pick word then pick punctuation twice then type", EXPECTED_RESULT, + mTextView.getText().toString()); + } + + public void testManualPickThenSpaceThenType() { + final String WORD1_TO_TYPE = "this"; + final String WORD2_TO_TYPE = " is"; + final String EXPECTED_RESULT = "this is"; + type(WORD1_TO_TYPE); + mLatinIME.pickSuggestionManually(0, WORD1_TO_TYPE); + type(WORD2_TO_TYPE); + assertEquals("manual pick then space then type", WORD1_TO_TYPE + WORD2_TO_TYPE, + mTextView.getText().toString()); + } + + public void testDeleteWholeComposingWord() { + final String WORD_TO_TYPE = "this"; + type(WORD_TO_TYPE); + for (int i = 0; i < WORD_TO_TYPE.length(); ++i) { + type(Keyboard.CODE_DELETE); + } + assertEquals("delete whole composing word", "", mTextView.getText().toString()); + } + + public void testManuallyPickedWordThenColon() { + final String WORD_TO_TYPE = "this"; + final String PUNCTUATION = ":"; + final String EXPECTED_RESULT = "this:"; + type(WORD_TO_TYPE); + mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE); + type(PUNCTUATION); + assertEquals("manually pick word then colon", + EXPECTED_RESULT, mTextView.getText().toString()); + } + + public void testManuallyPickedWordThenOpenParen() { + final String WORD_TO_TYPE = "this"; + final String PUNCTUATION = "("; + final String EXPECTED_RESULT = "this ("; + type(WORD_TO_TYPE); + mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE); + type(PUNCTUATION); + assertEquals("manually pick word then open paren", + EXPECTED_RESULT, mTextView.getText().toString()); + } + + public void testManuallyPickedWordThenCloseParen() { + final String WORD_TO_TYPE = "this"; + final String PUNCTUATION = ")"; + final String EXPECTED_RESULT = "this)"; + type(WORD_TO_TYPE); + mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE); + type(PUNCTUATION); + assertEquals("manually pick word then close paren", + EXPECTED_RESULT, mTextView.getText().toString()); + } + + public void testManuallyPickedWordThenSmiley() { + final String WORD_TO_TYPE = "this"; + final String SPECIAL_KEY = ":-)"; + final String EXPECTED_RESULT = "this :-)"; + type(WORD_TO_TYPE); + mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE); + mLatinIME.onTextInput(SPECIAL_KEY); + assertEquals("manually pick word then press the smiley key", + EXPECTED_RESULT, mTextView.getText().toString()); + } + + public void testManuallyPickedWordThenDotCom() { + final String WORD_TO_TYPE = "this"; + final String SPECIAL_KEY = ".com"; + final String EXPECTED_RESULT = "this.com"; + type(WORD_TO_TYPE); + mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE); + mLatinIME.onTextInput(SPECIAL_KEY); + assertEquals("manually pick word then press the .com key", + EXPECTED_RESULT, mTextView.getText().toString()); + } + + public void testTypeWordTypeDotThenPressDotCom() { + final String WORD_TO_TYPE = "this."; + final String SPECIAL_KEY = ".com"; + final String EXPECTED_RESULT = "this.com"; + type(WORD_TO_TYPE); + mLatinIME.onTextInput(SPECIAL_KEY); + assertEquals("type word type dot then press the .com key", + EXPECTED_RESULT, mTextView.getText().toString()); + } + + // TODO: Add some tests for non-BMP characters +} diff --git a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java index fec3e8ee1..7925d1a49 100644 --- a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java +++ b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java @@ -16,10 +16,7 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.latin.LocaleUtils; - import android.content.Context; -import android.content.res.Resources; import android.test.AndroidTestCase; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; @@ -30,24 +27,22 @@ import java.util.List; import java.util.Locale; public class SubtypeLocaleTests extends AndroidTestCase { - private static final String PACKAGE = LatinIME.class.getPackage().getName(); - - private Resources mRes; - private List<InputMethodSubtype> mKeyboardSubtypes = new ArrayList<InputMethodSubtype>(); + private List<InputMethodSubtype> mKeyboardSubtypes; @Override protected void setUp() throws Exception { super.setUp(); final Context context = getContext(); - mRes = context.getResources(); + final String packageName = context.getApplicationInfo().packageName; SubtypeLocale.init(context); final InputMethodManager imm = (InputMethodManager) context.getSystemService( Context.INPUT_METHOD_SERVICE); for (final InputMethodInfo imi : imm.getInputMethodList()) { - if (imi.getPackageName().equals(PACKAGE)) { + if (imi.getPackageName().equals(packageName)) { + mKeyboardSubtypes = new ArrayList<InputMethodSubtype>(); final int subtypeCount = imi.getSubtypeCount(); for (int i = 0; i < subtypeCount; ++i) { InputMethodSubtype subtype = imi.getSubtypeAt(i); @@ -58,37 +53,29 @@ public class SubtypeLocaleTests extends AndroidTestCase { break; } } - assertNotNull("Can not find input method " + PACKAGE, mKeyboardSubtypes); + assertNotNull("Can not find input method " + packageName, mKeyboardSubtypes); assertTrue("Can not find keyboard subtype", mKeyboardSubtypes.size() > 0); } - private String getStringWithLocale(int resId, Locale locale) { - final Locale savedLocale = Locale.getDefault(); - try { - Locale.setDefault(locale); - return mRes.getString(resId); - } finally { - Locale.setDefault(savedLocale); - } - } - public void testSubtypeLocale() { final StringBuilder messages = new StringBuilder(); int failedCount = 0; for (final InputMethodSubtype subtype : mKeyboardSubtypes) { - final String localeCode = subtype.getLocale(); - final Locale locale = LocaleUtils.constructLocaleFromString(localeCode); - // The locale name which will be displayed on spacebar. For example 'English (US)' or - // 'Francais (Canada)'. (c=\u008d) - final String displayName = SubtypeLocale.getFullDisplayName(locale); - // The subtype name in its locale. For example 'English (US) Keyboard' or - // 'Clavier Francais (Canada)'. (c=\u008d) - final String subtypeName = getStringWithLocale(subtype.getNameResId(), locale); - if (subtypeName.contains(displayName)) { + final Locale locale = LocaleUtils.constructLocaleFromString(subtype.getLocale()); + final String subtypeLocaleString = + subtype.containsExtraValueKey(LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE) + ? subtype.getExtraValueOf(LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE) + : subtype.getLocale(); + final Locale subtypeLocale = LocaleUtils.constructLocaleFromString(subtypeLocaleString); + // The subtype name in its locale. For example 'English (US)' or 'Deutsch (QWERTY)'. + final String subtypeName = SubtypeLocale.getFullDisplayName(subtypeLocale); + // The locale language name in its locale. + final String languageName = locale.getDisplayLanguage(locale); + if (!subtypeName.contains(languageName)) { failedCount++; messages.append(String.format( - "subtype name is '%s' and should contain locale '%s' name '%s'\n", - subtypeName, localeCode, displayName)); + "subtype name is '%s' and should contain locale '%s' language name '%s'\n", + subtypeName, subtypeLocale, languageName)); } } assertEquals(messages.toString(), 0, failedCount); diff --git a/tests/src/com/android/inputmethod/latin/SuggestHelper.java b/tests/src/com/android/inputmethod/latin/SuggestHelper.java index 464930f4c..0c023bd78 100644 --- a/tests/src/com/android/inputmethod/latin/SuggestHelper.java +++ b/tests/src/com/android/inputmethod/latin/SuggestHelper.java @@ -19,72 +19,54 @@ package com.android.inputmethod.latin; import android.content.Context; import android.text.TextUtils; -import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.KeyDetector; +import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardId; -import com.android.inputmethod.keyboard.LatinKeyboard; +import com.android.inputmethod.keyboard.KeyboardSet; import java.io.File; import java.util.Locale; public class SuggestHelper { protected final Suggest mSuggest; - protected final LatinKeyboard mKeyboard; + protected int mCorrectionMode; + protected final Keyboard mKeyboard; private final KeyDetector mKeyDetector; - public SuggestHelper(Context context, int dictionaryId, KeyboardId keyboardId) { + public SuggestHelper(Context context, int dictionaryId, KeyboardSet keyboardSet) { // Use null as the locale for Suggest so as to force it to use the internal dictionary // (and not try to find a dictionary provider for a specified locale) - mSuggest = new Suggest(context, dictionaryId, null); - mKeyboard = new LatinKeyboard.Builder(context).load(keyboardId).build(); - mKeyDetector = new KeyDetector(0); - init(); + this(new Suggest(context, dictionaryId, null), keyboardSet); } protected SuggestHelper(final Context context, final File dictionaryPath, - final long startOffset, final long length, final KeyboardId keyboardId, + final long startOffset, final long length, final KeyboardSet keyboardSet, final Locale locale) { - mSuggest = new Suggest(context, dictionaryPath, startOffset, length, null, locale); - mKeyboard = new LatinKeyboard.Builder(context).load(keyboardId).build(); - mKeyDetector = new KeyDetector(0); - init(); + this(new Suggest(context, dictionaryPath, startOffset, length, null, locale), keyboardSet); } - private void init() { - mSuggest.setCorrectionMode(Suggest.CORRECTION_FULL); + private SuggestHelper(final Suggest suggest, final KeyboardSet keyboardSet) { + mSuggest = suggest; + mKeyboard = keyboardSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET); + mKeyDetector = new KeyDetector(0); + + setCorrectionMode(Suggest.CORRECTION_FULL); mKeyDetector.setKeyboard(mKeyboard, 0, 0); mKeyDetector.setProximityCorrectionEnabled(true); mKeyDetector.setProximityThreshold(mKeyboard.mMostCommonKeyWidth); } public void setCorrectionMode(int correctionMode) { - mSuggest.setCorrectionMode(correctionMode); + mCorrectionMode = correctionMode; } public boolean hasMainDictionary() { return mSuggest.hasMainDictionary(); } - private void addKeyInfo(WordComposer word, char c) { - for (final Key key : mKeyboard.mKeys) { - if (key.mCode == c) { - final int x = key.mX + key.mWidth / 2; - final int y = key.mY + key.mHeight / 2; - final int[] codes = mKeyDetector.newCodeArray(); - mKeyDetector.getKeyIndexAndNearbyCodes(x, y, codes); - word.add(c, codes, x, y); - return; - } - } - word.add(c, new int[] { c }, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); - } - protected WordComposer createWordComposer(CharSequence s) { WordComposer word = new WordComposer(); - for (int i = 0; i < s.length(); i++) { - final char c = s.charAt(i); - addKeyInfo(word, c); - } + word.setComposingWord(s, mKeyboard, mKeyDetector); return word; } @@ -96,13 +78,13 @@ public class SuggestHelper { // TODO: This may be slow, but is OK for test so far. public SuggestedWords getSuggestions(CharSequence typed) { return mSuggest.getSuggestions(createWordComposer(typed), null, - mKeyboard.getProximityInfo()); + mKeyboard.getProximityInfo(), mCorrectionMode); } public CharSequence getFirstSuggestion(CharSequence typed) { WordComposer word = createWordComposer(typed); SuggestedWords suggestions = mSuggest.getSuggestions(word, null, - mKeyboard.getProximityInfo()); + mKeyboard.getProximityInfo(), mCorrectionMode); // Note that suggestions.getWord(0) is the word user typed. return suggestions.size() > 1 ? suggestions.getWord(1) : null; } @@ -110,7 +92,7 @@ public class SuggestHelper { public CharSequence getAutoCorrection(CharSequence typed) { WordComposer word = createWordComposer(typed); SuggestedWords suggestions = mSuggest.getSuggestions(word, null, - mKeyboard.getProximityInfo()); + mKeyboard.getProximityInfo(), mCorrectionMode); // Note that suggestions.getWord(0) is the word user typed. return (suggestions.size() > 1 && mSuggest.hasAutoCorrection()) ? suggestions.getWord(1) : null; @@ -119,7 +101,7 @@ public class SuggestHelper { public int getSuggestIndex(CharSequence typed, CharSequence expected) { WordComposer word = createWordComposer(typed); SuggestedWords suggestions = mSuggest.getSuggestions(word, null, - mKeyboard.getProximityInfo()); + mKeyboard.getProximityInfo(), mCorrectionMode); // Note that suggestions.getWord(0) is the word user typed. for (int i = 1; i < suggestions.size(); i++) { if (TextUtils.equals(suggestions.getWord(i), expected)) @@ -131,7 +113,8 @@ public class SuggestHelper { private void getBigramSuggestions(CharSequence previous, CharSequence typed) { if (!TextUtils.isEmpty(previous) && (typed.length() > 1)) { WordComposer firstChar = createWordComposer(Character.toString(typed.charAt(0))); - mSuggest.getSuggestions(firstChar, previous, mKeyboard.getProximityInfo()); + mSuggest.getSuggestions(firstChar, previous, mKeyboard.getProximityInfo(), + mCorrectionMode); } } @@ -139,7 +122,7 @@ public class SuggestHelper { WordComposer word = createWordComposer(typed); getBigramSuggestions(previous, typed); SuggestedWords suggestions = mSuggest.getSuggestions(word, previous, - mKeyboard.getProximityInfo()); + mKeyboard.getProximityInfo(), mCorrectionMode); return suggestions.size() > 1 ? suggestions.getWord(1) : null; } @@ -147,7 +130,7 @@ public class SuggestHelper { WordComposer word = createWordComposer(typed); getBigramSuggestions(previous, typed); SuggestedWords suggestions = mSuggest.getSuggestions(word, previous, - mKeyboard.getProximityInfo()); + mKeyboard.getProximityInfo(), mCorrectionMode); return (suggestions.size() > 1 && mSuggest.hasAutoCorrection()) ? suggestions.getWord(1) : null; } @@ -157,7 +140,7 @@ public class SuggestHelper { WordComposer word = createWordComposer(typed); getBigramSuggestions(previous, typed); SuggestedWords suggestions = mSuggest.getSuggestions(word, previous, - mKeyboard.getProximityInfo()); + mKeyboard.getProximityInfo(), mCorrectionMode); for (int i = 1; i < suggestions.size(); i++) { if (TextUtils.equals(suggestions.getWord(i), expected)) return i; diff --git a/tests/src/com/android/inputmethod/latin/SuggestTests.java b/tests/src/com/android/inputmethod/latin/SuggestTests.java index 4080f34be..e12ae58c4 100644 --- a/tests/src/com/android/inputmethod/latin/SuggestTests.java +++ b/tests/src/com/android/inputmethod/latin/SuggestTests.java @@ -33,7 +33,7 @@ public class SuggestTests extends SuggestTestsBase { final Locale locale = Locale.US; mHelper = new SuggestHelper( getContext(), mTestPackageFile, dict.getStartOffset(), dict.getLength(), - createKeyboardId(locale, Configuration.ORIENTATION_PORTRAIT), locale); + createKeyboardSet(locale, Configuration.ORIENTATION_PORTRAIT), locale); mHelper.setCorrectionMode(Suggest.CORRECTION_FULL_BIGRAM); } @@ -183,7 +183,8 @@ public class SuggestTests extends SuggestTestsBase { "part", mHelper.getBigramAutoCorrection("about", "pa")); // TODO: The following test fails. // suggested("single: said", "said", mHelper.getAutoCorrection("sa")); - suggested("bigram: from sa[me]", - "same", mHelper.getBigramAutoCorrection("from", "sa")); + // TODO: The following test fails due to "transpose correction". + // suggested("bigram: from sa[me]", + // "same", mHelper.getBigramAutoCorrection("from", "sa")); } } diff --git a/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java b/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java index 058a3e7c0..73e34ba6f 100644 --- a/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java +++ b/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java @@ -19,11 +19,12 @@ package com.android.inputmethod.latin; import android.content.res.AssetFileDescriptor; import android.content.res.Configuration; import android.test.AndroidTestCase; +import android.text.InputType; import android.text.TextUtils; import android.util.DisplayMetrics; import android.view.inputmethod.EditorInfo; -import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.KeyboardSet; import java.io.File; import java.io.InputStream; @@ -38,7 +39,12 @@ public class SuggestTestsBase extends AndroidTestCase { mTestPackageFile = new File(getTestContext().getApplicationInfo().sourceDir); } - protected KeyboardId createKeyboardId(Locale locale, int orientation) { + protected KeyboardSet createKeyboardSet(Locale locale, int orientation) { + return createKeyboardSet(locale, orientation, false); + } + + protected KeyboardSet createKeyboardSet(Locale locale, int orientation, + boolean touchPositionCorrectionEnabled) { final DisplayMetrics dm = getContext().getResources().getDisplayMetrics(); final int width; if (orientation == Configuration.ORIENTATION_LANDSCAPE) { @@ -50,10 +56,12 @@ public class SuggestTestsBase extends AndroidTestCase { + "orientation=" + orientation); return null; } - return new KeyboardId(locale.toString() + " keyboard", - com.android.inputmethod.latin.R.xml.kbd_qwerty, locale, orientation, width, - KeyboardId.MODE_TEXT, new EditorInfo(), false, KeyboardId.F2KEY_MODE_NONE, - false, false, false); + final EditorInfo editorInfo = new EditorInfo(); + editorInfo.inputType = InputType.TYPE_CLASS_TEXT; + final KeyboardSet.Builder builder = new KeyboardSet.Builder(getContext(), editorInfo); + builder.setScreenGeometry(orientation, width); + builder.setSubtype(locale, true, touchPositionCorrectionEnabled); + return builder.build(); } protected InputStream openTestRawResource(int resIdInTest) { diff --git a/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java b/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java index 023e20a10..74fadf76b 100644 --- a/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java +++ b/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java @@ -16,11 +16,11 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.keyboard.KeyboardId; - import android.content.Context; import android.text.TextUtils; +import com.android.inputmethod.keyboard.KeyboardSet; + import java.io.File; import java.util.Locale; import java.util.StringTokenizer; @@ -31,14 +31,14 @@ public class UserBigramSuggestHelper extends SuggestHelper { public UserBigramSuggestHelper(final Context context, final File dictionaryPath, final long startOffset, final long length, final int userBigramMax, - final int userBigramDelete, final KeyboardId keyboardId, final Locale locale) { - super(context, dictionaryPath, startOffset, length, keyboardId, locale); + final int userBigramDelete, final KeyboardSet keyboardSet, final Locale locale) { + super(context, dictionaryPath, startOffset, length, keyboardSet, locale); mContext = context; mUserBigram = new UserBigramDictionary(context, null, locale.toString(), Suggest.DIC_USER); mUserBigram.setDatabaseMax(userBigramMax); mUserBigram.setDatabaseDelete(userBigramDelete); - mSuggest.setCorrectionMode(Suggest.CORRECTION_FULL_BIGRAM); + setCorrectionMode(Suggest.CORRECTION_FULL_BIGRAM); mSuggest.setUserBigramDictionary(mUserBigram); } @@ -59,7 +59,8 @@ public class UserBigramSuggestHelper extends SuggestHelper { flushUserBigrams(); if (!TextUtils.isEmpty(previous) && !TextUtils.isEmpty(Character.toString(typed))) { WordComposer firstChar = createWordComposer(Character.toString(typed)); - mSuggest.getSuggestions(firstChar, previous, mKeyboard.getProximityInfo()); + mSuggest.getSuggestions(firstChar, previous, mKeyboard.getProximityInfo(), + mCorrectionMode); boolean reloading = mUserBigram.reloadDictionaryIfRequired(); if (reloading) mUserBigram.waitForDictionaryLoading(); mUserBigram.getBigrams(firstChar, previous, mSuggest); diff --git a/tests/src/com/android/inputmethod/latin/UserBigramSuggestTests.java b/tests/src/com/android/inputmethod/latin/UserBigramSuggestTests.java index 2bc0aabc0..2b88a7ca6 100644 --- a/tests/src/com/android/inputmethod/latin/UserBigramSuggestTests.java +++ b/tests/src/com/android/inputmethod/latin/UserBigramSuggestTests.java @@ -23,7 +23,7 @@ import com.android.inputmethod.latin.tests.R; import java.util.Locale; public class UserBigramSuggestTests extends SuggestTestsBase { - private static final int SUGGESTION_STARTS = 6; + private static final int SUGGESTION_STARTS = 1; private static final int MAX_DATA = 20; private static final int DELETE_DATA = 10; @@ -37,7 +37,7 @@ public class UserBigramSuggestTests extends SuggestTestsBase { mHelper = new UserBigramSuggestHelper( getContext(), mTestPackageFile, dict.getStartOffset(), dict.getLength(), MAX_DATA, DELETE_DATA, - createKeyboardId(locale, Configuration.ORIENTATION_PORTRAIT), locale); + createKeyboardSet(locale, Configuration.ORIENTATION_PORTRAIT), locale); } /************************** Tests ************************/ diff --git a/tests/src/com/android/inputmethod/latin/UtilsTests.java b/tests/src/com/android/inputmethod/latin/UtilsTests.java index 5c0b03a0a..2ef4e2ff5 100644 --- a/tests/src/com/android/inputmethod/latin/UtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/UtilsTests.java @@ -18,8 +18,6 @@ package com.android.inputmethod.latin; import android.test.AndroidTestCase; -import com.android.inputmethod.latin.tests.R; - public class UtilsTests extends AndroidTestCase { // The following is meant to be a reasonable default for diff --git a/tools/Android.mk b/tools/Android.mk index 8f1acc55a..91b2fbbb0 100644 --- a/tools/Android.mk +++ b/tools/Android.mk @@ -12,6 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -LOCAL_PATH := $(call my-dir) - -include $(call all-makefiles-under,$(LOCAL_PATH)) +include $(call all-subdir-makefiles) diff --git a/tools/makedict/src/com/android/inputmethod/latin/BinaryDictInputOutput.java b/tools/makedict/src/com/android/inputmethod/latin/BinaryDictInputOutput.java index 92f402d3e..7aadc677b 100644 --- a/tools/makedict/src/com/android/inputmethod/latin/BinaryDictInputOutput.java +++ b/tools/makedict/src/com/android/inputmethod/latin/BinaryDictInputOutput.java @@ -26,6 +26,7 @@ import java.io.OutputStream; import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.Arrays; +import java.util.Iterator; import java.util.Map; import java.util.TreeMap; @@ -44,8 +45,9 @@ public class BinaryDictInputOutput { * a | 11 = 3 bytes : FLAG_GROUP_ADDRESS_TYPE_THREEBYTES * g | has several chars ? 1 bit, 1 = yes, 0 = no : FLAG_HAS_MULTIPLE_CHARS * s | has a terminal ? 1 bit, 1 = yes, 0 = no : FLAG_IS_TERMINAL - * | reserved 1 bit, 1 = yes, 0 = no + * | has shortcut targets ? 1 bit, 1 = yes, 0 = no : FLAG_HAS_SHORTCUT_TARGETS * | has bigrams ? 1 bit, 1 = yes, 0 = no : FLAG_HAS_BIGRAMS + * | is shortcut only ? 1 bit, 1 = yes, 0 = no : FLAG_IS_SHORTCUT_ONLY * * c | IF FLAG_HAS_MULTIPLE_CHARS * h | char, char, char, char n * (1 or 3 bytes) : use CharGroupInfo for i/o helpers @@ -71,6 +73,8 @@ public class BinaryDictInputOutput { * d * dress * + * | IF FLAG_IS_TERMINAL && FLAG_HAS_SHORTCUT_TARGETS + * | shortcut targets address list * | IF FLAG_IS_TERMINAL && FLAG_HAS_BIGRAMS * | bigrams address list * @@ -126,7 +130,9 @@ public class BinaryDictInputOutput { private static final int FLAG_HAS_MULTIPLE_CHARS = 0x20; private static final int FLAG_IS_TERMINAL = 0x10; + private static final int FLAG_HAS_SHORTCUT_TARGETS = 0x08; private static final int FLAG_HAS_BIGRAMS = 0x04; + private static final int FLAG_IS_SHORTCUT_ONLY = 0x02; private static final int FLAG_ATTRIBUTE_HAS_NEXT = 0x80; private static final int FLAG_ATTRIBUTE_OFFSET_NEGATIVE = 0x40; @@ -138,7 +144,6 @@ public class BinaryDictInputOutput { private static final int GROUP_CHARACTERS_TERMINATOR = 0x1F; - private static final int GROUP_COUNT_SIZE = 1; private static final int GROUP_TERMINATOR_SIZE = 1; private static final int GROUP_FLAGS_SIZE = 1; private static final int GROUP_FREQUENCY_SIZE = 1; @@ -149,9 +154,8 @@ public class BinaryDictInputOutput { private static final int NO_CHILDREN_ADDRESS = Integer.MIN_VALUE; private static final int INVALID_CHARACTER = -1; - // Limiting to 127 for upward compatibility - // TODO: implement a scheme to be able to shoot 256 chargroups in a node - private static final int MAX_CHARGROUPS_IN_A_NODE = 127; + private static final int MAX_CHARGROUPS_FOR_ONE_BYTE_CHARGROUP_COUNT = 0x7F; // 127 + private static final int MAX_CHARGROUPS_IN_A_NODE = 0x7FFF; // 32767 private static final int MAX_TERMINAL_FREQUENCY = 255; @@ -261,6 +265,31 @@ public class BinaryDictInputOutput { } /** + * Compute the binary size of the group count + * @param count the group count + * @return the size of the group count, either 1 or 2 bytes. + */ + private static int getGroupCountSize(final int count) { + if (MAX_CHARGROUPS_FOR_ONE_BYTE_CHARGROUP_COUNT >= count) { + return 1; + } else if (MAX_CHARGROUPS_IN_A_NODE >= count) { + return 2; + } else { + throw new RuntimeException("Can't have more than " + MAX_CHARGROUPS_IN_A_NODE + + " groups in a node (found " + count +")"); + } + } + + /** + * Compute the binary size of the group count for a node + * @param node the node + * @return the size of the group count, either 1 or 2 bytes. + */ + private static int getGroupCountSize(final Node node) { + return getGroupCountSize(node.mData.size()); + } + + /** * Compute the maximum size of a CharGroup, assuming 3-byte addresses for everything. * * @param group the CharGroup to compute the size of. @@ -271,10 +300,13 @@ public class BinaryDictInputOutput { // If terminal, one byte for the frequency if (group.isTerminal()) size += GROUP_FREQUENCY_SIZE; size += GROUP_MAX_ADDRESS_SIZE; // For children address + if (null != group.mShortcutTargets) { + size += (GROUP_ATTRIBUTE_FLAGS_SIZE + GROUP_ATTRIBUTE_MAX_ADDRESS_SIZE) + * group.mShortcutTargets.size(); + } if (null != group.mBigrams) { - for (WeightedString bigram : group.mBigrams) { - size += GROUP_ATTRIBUTE_FLAGS_SIZE + GROUP_ATTRIBUTE_MAX_ADDRESS_SIZE; - } + size += (GROUP_ATTRIBUTE_FLAGS_SIZE + GROUP_ATTRIBUTE_MAX_ADDRESS_SIZE) + * group.mBigrams.size(); } return size; } @@ -286,7 +318,7 @@ public class BinaryDictInputOutput { * @param node the node to compute the maximum size of. */ private static void setNodeMaximumSize(Node node) { - int size = GROUP_COUNT_SIZE; + int size = getGroupCountSize(node); for (CharGroup g : node.mData) { final int groupSize = getCharGroupMaximumSize(g); g.mCachedSize = groupSize; @@ -303,6 +335,13 @@ public class BinaryDictInputOutput { } /** + * Helper method to find out if a character info is a shortcut only. + */ + private static boolean isShortcutOnly(final CharGroupInfo info) { + return 0 != (info.mFlags & FLAG_IS_SHORTCUT_ONLY); + } + + /** * Compute the size, in bytes, that an address will occupy. * * This can be used either for children addresses (which are always positive) or for @@ -378,7 +417,7 @@ public class BinaryDictInputOutput { * @param dict the dictionary in which the word/attributes are to be found. */ private static void computeActualNodeSize(Node node, FusionDictionary dict) { - int size = GROUP_COUNT_SIZE; + int size = getGroupCountSize(node); for (CharGroup group : node.mData) { int groupSize = GROUP_FLAGS_SIZE + getGroupCharactersSize(group); if (group.isTerminal()) groupSize += GROUP_FREQUENCY_SIZE; @@ -387,6 +426,15 @@ public class BinaryDictInputOutput { final int offset = group.mChildren.mCachedAddress - offsetBasePoint; groupSize += getByteSize(offset); } + if (null != group.mShortcutTargets) { + for (WeightedString target : group.mShortcutTargets) { + final int offsetBasePoint = groupSize + node.mCachedAddress + size + + GROUP_FLAGS_SIZE; + final int addressOfTarget = findAddressOfWord(dict, target.mWord); + final int offset = addressOfTarget - offsetBasePoint; + groupSize += getByteSize(offset) + GROUP_FLAGS_SIZE; + } + } if (null != group.mBigrams) { for (WeightedString bigram : group.mBigrams) { final int offsetBasePoint = groupSize + node.mCachedAddress + size @@ -412,12 +460,13 @@ public class BinaryDictInputOutput { int nodeOffset = 0; for (Node n : flatNodes) { n.mCachedAddress = nodeOffset; + int groupCountSize = getGroupCountSize(n); int groupOffset = 0; for (CharGroup g : n.mData) { - g.mCachedAddress = GROUP_COUNT_SIZE + nodeOffset + groupOffset; + g.mCachedAddress = groupCountSize + nodeOffset + groupOffset; groupOffset += g.mCachedSize; } - if (groupOffset + GROUP_COUNT_SIZE != n.mCachedSize) { + if (groupOffset + groupCountSize != n.mCachedSize) { throw new RuntimeException("Bug : Stored and computed node size differ"); } nodeOffset += n.mCachedSize; @@ -545,7 +594,21 @@ public class BinaryDictInputOutput { throw new RuntimeException("Node with a strange address"); } } - if (null != group.mBigrams) flags |= FLAG_HAS_BIGRAMS; + if (null != group.mShortcutTargets) { + if (0 == group.mShortcutTargets.size()) { + throw new RuntimeException("0-sized shortcut list must be null"); + } + flags |= FLAG_HAS_SHORTCUT_TARGETS; + } + if (null != group.mBigrams) { + if (0 == group.mBigrams.size()) { + throw new RuntimeException("0-sized bigram list must be null"); + } + flags |= FLAG_HAS_BIGRAMS; + } + if (group.mIsShortcutOnly) { + flags |= FLAG_IS_SHORTCUT_ONLY; + } return flags; } @@ -592,13 +655,20 @@ public class BinaryDictInputOutput { private static int writePlacedNode(FusionDictionary dict, byte[] buffer, Node node) { int index = node.mCachedAddress; - final int size = node.mData.size(); - if (size > MAX_CHARGROUPS_IN_A_NODE) - throw new RuntimeException("A node has a group count over 127 (" + size + ")."); - - buffer[index++] = (byte)size; + final int groupCount = node.mData.size(); + final int countSize = getGroupCountSize(node); + if (1 == countSize) { + buffer[index++] = (byte)groupCount; + } else if (2 == countSize) { + // We need to signal 2-byte size by setting the top bit of the MSB to 1, so + // we | 0x80 to do this. + buffer[index++] = (byte)((groupCount >> 8) | 0x80); + buffer[index++] = (byte)(groupCount & 0xFF); + } else { + throw new RuntimeException("Strange size from getGroupCountSize : " + countSize); + } int groupAddress = index; - for (int i = 0; i < size; ++i) { + for (int i = 0; i < groupCount; ++i) { CharGroup group = node.mData.get(i); if (index != group.mCachedAddress) throw new RuntimeException("Bug: write index is not " + "the same as the cached address of the group"); @@ -624,20 +694,36 @@ public class BinaryDictInputOutput { index += shift; groupAddress += shift; + // Write shortcuts + if (null != group.mShortcutTargets) { + final Iterator shortcutIterator = group.mShortcutTargets.iterator(); + while (shortcutIterator.hasNext()) { + final WeightedString target = (WeightedString)shortcutIterator.next(); + final int addressOfTarget = findAddressOfWord(dict, target.mWord); + ++groupAddress; + final int offset = addressOfTarget - groupAddress; + int shortcutFlags = makeAttributeFlags(shortcutIterator.hasNext(), offset, + target.mFrequency); + buffer[index++] = (byte)shortcutFlags; + final int shortcutShift = writeVariableAddress(buffer, index, Math.abs(offset)); + index += shortcutShift; + groupAddress += shortcutShift; + } + } // Write bigrams if (null != group.mBigrams) { - int remainingBigrams = group.mBigrams.size(); - for (WeightedString bigram : group.mBigrams) { - boolean more = remainingBigrams > 1; + final Iterator bigramIterator = group.mBigrams.iterator(); + while (bigramIterator.hasNext()) { + final WeightedString bigram = (WeightedString)bigramIterator.next(); final int addressOfBigram = findAddressOfWord(dict, bigram.mWord); ++groupAddress; final int offset = addressOfBigram - groupAddress; - int bigramFlags = makeAttributeFlags(more, offset, bigram.mFrequency); + int bigramFlags = makeAttributeFlags(bigramIterator.hasNext(), offset, + bigram.mFrequency); buffer[index++] = (byte)bigramFlags; final int bigramShift = writeVariableAddress(buffer, index, Math.abs(offset)); index += bigramShift; groupAddress += bigramShift; - --remainingBigrams; } } @@ -814,14 +900,43 @@ public class BinaryDictInputOutput { childrenAddress = NO_CHILDREN_ADDRESS; break; } + ArrayList<PendingAttribute> shortcutTargets = null; + if (0 != (flags & FLAG_HAS_SHORTCUT_TARGETS)) { + shortcutTargets = new ArrayList<PendingAttribute>(); + while (true) { + final int targetFlags = source.readUnsignedByte(); + ++addressPointer; + final int sign = 0 == (targetFlags & FLAG_ATTRIBUTE_OFFSET_NEGATIVE) ? 1 : -1; + int targetAddress = addressPointer; + switch (targetFlags & MASK_ATTRIBUTE_ADDRESS_TYPE) { + case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE: + targetAddress += sign * source.readUnsignedByte(); + addressPointer += 1; + break; + case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES: + targetAddress += sign * source.readUnsignedShort(); + addressPointer += 2; + break; + case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES: + final int offset = ((source.readUnsignedByte() << 16) + + source.readUnsignedShort()); + targetAddress += sign * offset; + addressPointer += 3; + break; + default: + throw new RuntimeException("Has shortcut targets with no address"); + } + shortcutTargets.add(new PendingAttribute(targetFlags & FLAG_ATTRIBUTE_FREQUENCY, + targetAddress)); + if (0 == (targetFlags & FLAG_ATTRIBUTE_HAS_NEXT)) break; + } + } ArrayList<PendingAttribute> bigrams = null; if (0 != (flags & FLAG_HAS_BIGRAMS)) { bigrams = new ArrayList<PendingAttribute>(); - boolean more = true; - while (more) { - int bigramFlags = source.readUnsignedByte(); + while (true) { + final int bigramFlags = source.readUnsignedByte(); ++addressPointer; - more = (0 != (bigramFlags & FLAG_ATTRIBUTE_HAS_NEXT)); final int sign = 0 == (bigramFlags & FLAG_ATTRIBUTE_OFFSET_NEGATIVE) ? 1 : -1; int bigramAddress = addressPointer; switch (bigramFlags & MASK_ATTRIBUTE_ADDRESS_TYPE) { @@ -840,14 +955,28 @@ public class BinaryDictInputOutput { addressPointer += 3; break; default: - throw new RuntimeException("Has attribute with no address"); + throw new RuntimeException("Has bigrams with no address"); } bigrams.add(new PendingAttribute(bigramFlags & FLAG_ATTRIBUTE_FREQUENCY, bigramAddress)); + if (0 == (bigramFlags & FLAG_ATTRIBUTE_HAS_NEXT)) break; } } return new CharGroupInfo(originalGroupAddress, addressPointer, flags, characters, frequency, - childrenAddress, bigrams); + childrenAddress, shortcutTargets, bigrams); + } + + /** + * Reads and returns the char group count out of a file and forwards the pointer. + */ + private static int readCharGroupCount(RandomAccessFile source) throws IOException { + final int msb = source.readUnsignedByte(); + if (MAX_CHARGROUPS_FOR_ONE_BYTE_CHARGROUP_COUNT >= msb) { + return msb; + } else { + return ((MAX_CHARGROUPS_FOR_ONE_BYTE_CHARGROUP_COUNT & msb) << 8) + + source.readUnsignedByte(); + } } /** @@ -863,8 +992,8 @@ public class BinaryDictInputOutput { int address) throws IOException { final long originalPointer = source.getFilePointer(); source.seek(headerSize); - final int count = source.readUnsignedByte(); - int groupOffset = 1; // 1 for the group count + final int count = readCharGroupCount(source); + int groupOffset = getGroupCountSize(count); final StringBuilder builder = new StringBuilder(); String result = null; @@ -920,11 +1049,19 @@ public class BinaryDictInputOutput { Map<Integer, Node> reverseNodeMap, Map<Integer, CharGroup> reverseGroupMap) throws IOException { final int nodeOrigin = (int)(source.getFilePointer() - headerSize); - final int count = source.readUnsignedByte(); + final int count = readCharGroupCount(source); final ArrayList<CharGroup> nodeContents = new ArrayList<CharGroup>(); - int groupOffset = nodeOrigin + 1; // 1 byte for the group count + int groupOffset = nodeOrigin + getGroupCountSize(count); for (int i = count; i > 0; --i) { CharGroupInfo info = readCharGroup(source, groupOffset); + ArrayList<WeightedString> shortcutTargets = null; + if (null != info.mShortcutTargets) { + shortcutTargets = new ArrayList<WeightedString>(); + for (PendingAttribute target : info.mShortcutTargets) { + final String word = getWordAtAddress(source, headerSize, target.mAddress); + shortcutTargets.add(new WeightedString(word, target.mFrequency)); + } + } ArrayList<WeightedString> bigrams = null; if (null != info.mBigrams) { bigrams = new ArrayList<WeightedString>(); @@ -942,11 +1079,12 @@ public class BinaryDictInputOutput { source.seek(currentPosition); } nodeContents.add( - new CharGroup(info.mCharacters, bigrams, info.mFrequency, - children)); + new CharGroup(info.mCharacters, shortcutTargets, bigrams, info.mFrequency, + children, isShortcutOnly(info))); } else { nodeContents.add( - new CharGroup(info.mCharacters, bigrams, info.mFrequency)); + new CharGroup(info.mCharacters, shortcutTargets, bigrams, info.mFrequency, + isShortcutOnly(info))); } groupOffset = info.mEndAddress; } @@ -996,7 +1134,7 @@ public class BinaryDictInputOutput { new FusionDictionary.DictionaryOptions()); if (null != dict) { for (Word w : dict) { - newDict.add(w.mWord, w.mFrequency, w.mBigrams); + newDict.add(w.mWord, w.mFrequency, w.mShortcutTargets, w.mBigrams); } } diff --git a/tools/makedict/src/com/android/inputmethod/latin/CharGroupInfo.java b/tools/makedict/src/com/android/inputmethod/latin/CharGroupInfo.java index 6badfd13a..759cd452d 100644 --- a/tools/makedict/src/com/android/inputmethod/latin/CharGroupInfo.java +++ b/tools/makedict/src/com/android/inputmethod/latin/CharGroupInfo.java @@ -29,10 +29,12 @@ public class CharGroupInfo { public final int[] mCharacters; public final int mFrequency; public final int mChildrenAddress; + public final ArrayList<PendingAttribute> mShortcutTargets; public final ArrayList<PendingAttribute> mBigrams; public CharGroupInfo(final int originalAddress, final int endAddress, final int flags, final int[] characters, final int frequency, final int childrenAddress, + final ArrayList<PendingAttribute> shortcutTargets, final ArrayList<PendingAttribute> bigrams) { mOriginalAddress = originalAddress; mEndAddress = endAddress; @@ -40,6 +42,7 @@ public class CharGroupInfo { mCharacters = characters; mFrequency = frequency; mChildrenAddress = childrenAddress; + mShortcutTargets = shortcutTargets; mBigrams = bigrams; } } diff --git a/tools/makedict/src/com/android/inputmethod/latin/DictionaryMaker.java b/tools/makedict/src/com/android/inputmethod/latin/DictionaryMaker.java index 1ba01075e..2fcd5750a 100644 --- a/tools/makedict/src/com/android/inputmethod/latin/DictionaryMaker.java +++ b/tools/makedict/src/com/android/inputmethod/latin/DictionaryMaker.java @@ -39,11 +39,13 @@ public class DictionaryMaker { private final static String OPTION_VERSION_2 = "-2"; private final static String OPTION_INPUT_SOURCE = "-s"; private final static String OPTION_INPUT_BIGRAM_XML = "-b"; + private final static String OPTION_INPUT_SHORTCUT_XML = "-c"; private final static String OPTION_OUTPUT_BINARY = "-d"; private final static String OPTION_OUTPUT_XML = "-x"; private final static String OPTION_HELP = "-h"; public final String mInputBinary; public final String mInputUnigramXml; + public final String mInputShortcutXml; public final String mInputBigramXml; public final String mOutputBinary; public final String mOutputXml; @@ -72,8 +74,9 @@ public class DictionaryMaker { private void displayHelp() { MakedictLog.i("Usage: makedict " - + "[-s <unigrams.xml> [-b <bigrams.xml>] | -s <binary input>] " - + " [-d <binary output>] [-x <xml output>] [-2]\n" + + "[-s <unigrams.xml> [-b <bigrams.xml>] [-c <shortcuts.xml>] " + + "| -s <binary input>] " + + "[-d <binary output>] [-x <xml output>] [-2]\n" + "\n" + " Converts a source dictionary file to one or several outputs.\n" + " Source can be an XML file, with an optional XML bigrams file, or a\n" @@ -90,6 +93,7 @@ public class DictionaryMaker { } String inputBinary = null; String inputUnigramXml = null; + String inputShortcutXml = null; String inputBigramXml = null; String outputBinary = null; String outputXml = null; @@ -105,7 +109,8 @@ public class DictionaryMaker { } else { // All these options need an argument if (args.isEmpty()) { - throw new RuntimeException("Option " + arg + " requires an argument"); + throw new IllegalArgumentException("Option " + arg + " is unknown or " + + "requires an argument"); } String filename = args.get(0); args.remove(0); @@ -115,12 +120,16 @@ public class DictionaryMaker { } else { inputUnigramXml = filename; } + } else if (OPTION_INPUT_SHORTCUT_XML.equals(arg)) { + inputShortcutXml = filename; } else if (OPTION_INPUT_BIGRAM_XML.equals(arg)) { inputBigramXml = filename; } else if (OPTION_OUTPUT_BINARY.equals(arg)) { outputBinary = filename; } else if (OPTION_OUTPUT_XML.equals(arg)) { outputXml = filename; + } else { + throw new IllegalArgumentException("Unknown option : " + arg); } } } else { @@ -133,13 +142,14 @@ public class DictionaryMaker { } else if (null == outputBinary) { outputBinary = arg; } else { - throw new RuntimeException("Several output binary files specified"); + throw new IllegalArgumentException("Several output binary files specified"); } } } mInputBinary = inputBinary; mInputUnigramXml = inputUnigramXml; + mInputShortcutXml = inputShortcutXml; mInputBigramXml = inputBigramXml; mOutputBinary = outputBinary; mOutputXml = outputXml; @@ -167,7 +177,7 @@ public class DictionaryMaker { if (null != args.mInputBinary) { return readBinaryFile(args.mInputBinary); } else if (null != args.mInputUnigramXml) { - return readXmlFile(args.mInputUnigramXml, args.mInputBigramXml); + return readXmlFile(args.mInputUnigramXml, args.mInputShortcutXml, args.mInputBigramXml); } else { throw new RuntimeException("No input file specified"); } @@ -192,6 +202,7 @@ public class DictionaryMaker { * Read a dictionary from a unigram XML file, and optionally a bigram XML file. * * @param unigramXmlFilename the name of the unigram XML file. May not be null. + * @param shortcutXmlFilename the name of the shortcut XML file, or null if there is none. * @param bigramXmlFilename the name of the bigram XML file. Pass null if there are no bigrams. * @return the read dictionary. * @throws FileNotFoundException if one of the files can't be found @@ -200,12 +211,14 @@ public class DictionaryMaker { * @throws ParserConfigurationException if the system can't create a SAX parser */ private static FusionDictionary readXmlFile(final String unigramXmlFilename, - final String bigramXmlFilename) throws FileNotFoundException, SAXException, - IOException, ParserConfigurationException { + final String shortcutXmlFilename, final String bigramXmlFilename) + throws FileNotFoundException, SAXException, IOException, ParserConfigurationException { final FileInputStream unigrams = new FileInputStream(new File(unigramXmlFilename)); + final FileInputStream shortcuts = null == shortcutXmlFilename ? null : + new FileInputStream(new File(shortcutXmlFilename)); final FileInputStream bigrams = null == bigramXmlFilename ? null : new FileInputStream(new File(bigramXmlFilename)); - return XmlDictInputOutput.readDictionaryXml(unigrams, bigrams); + return XmlDictInputOutput.readDictionaryXml(unigrams, shortcuts, bigrams); } /** diff --git a/tools/makedict/src/com/android/inputmethod/latin/FusionDictionary.java b/tools/makedict/src/com/android/inputmethod/latin/FusionDictionary.java index f6220eea2..08143d3ea 100644 --- a/tools/makedict/src/com/android/inputmethod/latin/FusionDictionary.java +++ b/tools/makedict/src/com/android/inputmethod/latin/FusionDictionary.java @@ -68,7 +68,7 @@ public class FusionDictionary implements Iterable<Word> { } /** - * A group of characters, with a frequency, shortcuts, bigrams, and children. + * A group of characters, with a frequency, shortcut targets, bigrams, and children. * * This is the central class of the in-memory representation. A CharGroup is what can * be seen as a traditional "trie node", except it can hold several characters at the @@ -82,25 +82,39 @@ public class FusionDictionary implements Iterable<Word> { public static class CharGroup { public static final int NOT_A_TERMINAL = -1; final int mChars[]; + final ArrayList<WeightedString> mShortcutTargets; final ArrayList<WeightedString> mBigrams; final int mFrequency; // NOT_A_TERMINAL == mFrequency indicates this is not a terminal. + final boolean mIsShortcutOnly; // Only valid if this is a terminal. Node mChildren; // The two following members to help with binary generation int mCachedSize; int mCachedAddress; - public CharGroup(final int[] chars, - final ArrayList<WeightedString> bigrams, final int frequency) { + public CharGroup(final int[] chars, final ArrayList<WeightedString> shortcutTargets, + final ArrayList<WeightedString> bigrams, final int frequency, + final boolean isShortcutOnly) { mChars = chars; mFrequency = frequency; + mIsShortcutOnly = isShortcutOnly; + if (mIsShortcutOnly && NOT_A_TERMINAL == mFrequency) { + throw new RuntimeException("A node must be a terminal to be a shortcut only"); + } + mShortcutTargets = shortcutTargets; mBigrams = bigrams; mChildren = null; } - public CharGroup(final int[] chars, - final ArrayList<WeightedString> bigrams, final int frequency, final Node children) { + public CharGroup(final int[] chars, final ArrayList<WeightedString> shortcutTargets, + final ArrayList<WeightedString> bigrams, final int frequency, final Node children, + final boolean isShortcutOnly) { mChars = chars; mFrequency = frequency; + mIsShortcutOnly = isShortcutOnly; + if (mIsShortcutOnly && NOT_A_TERMINAL == mFrequency) { + throw new RuntimeException("A node must be a terminal to be a shortcut only"); + } + mShortcutTargets = shortcutTargets; mBigrams = bigrams; mChildren = children; } @@ -150,13 +164,31 @@ public class FusionDictionary implements Iterable<Word> { static private int[] getCodePoints(String word) { final int wordLength = word.length(); int[] array = new int[word.codePointCount(0, wordLength)]; - for (int i = 0; i < wordLength; ++i) { + for (int i = 0; i < wordLength; i = word.offsetByCodePoints(i, 1)) { array[i] = word.codePointAt(i); } return array; } /** + * Helper method to add all words in a list as 0-frequency entries + * + * These words are added when shortcuts targets or bigrams are not found in the dictionary + * yet. The same words may be added later with an actual frequency - this is handled by + * the private version of add(). + */ + private void addNeutralWords(final ArrayList<WeightedString> words) { + if (null != words) { + for (WeightedString word : words) { + final CharGroup t = findWordInTree(mRoot, word.mWord); + if (null == t) { + add(getCodePoints(word.mWord), 0, null, null, false /* isShortcutOnly */); + } + } + } + } + + /** * Helper method to add a word as a string. * * This method adds a word to the dictionary with the given frequency. Optional @@ -165,18 +197,19 @@ public class FusionDictionary implements Iterable<Word> { * * @param word the word to add. * @param frequency the frequency of the word, in the range [0..255]. + * @param shortcutTargets a list of shortcut targets for this word, or null. * @param bigrams a list of bigrams, or null. */ - public void add(String word, int frequency, ArrayList<WeightedString> bigrams) { + public void add(final String word, final int frequency, + final ArrayList<WeightedString> shortcutTargets, + final ArrayList<WeightedString> bigrams) { + if (null != shortcutTargets) { + addNeutralWords(shortcutTargets); + } if (null != bigrams) { - for (WeightedString bigram : bigrams) { - final CharGroup t = findWordInTree(mRoot, bigram.mWord); - if (null == t) { - add(getCodePoints(bigram.mWord), 0, null); - } - } + addNeutralWords(bigrams); } - add(getCodePoints(word), frequency, bigrams); + add(getCodePoints(word), frequency, shortcutTargets, bigrams, false /* isShortcutOnly */); } /** @@ -198,16 +231,37 @@ public class FusionDictionary implements Iterable<Word> { } /** + * Helper method to add a shortcut that should not be a dictionary word. + * + * @param word the word to add. + * @param frequency the frequency of the word, in the range [0..255]. + * @param shortcutTargets a list of shortcut targets. May not be null. + */ + public void addShortcutOnly(final String word, final int frequency, + final ArrayList<WeightedString> shortcutTargets) { + if (null == shortcutTargets) { + throw new RuntimeException("Can't add a shortcut without targets"); + } + addNeutralWords(shortcutTargets); + add(getCodePoints(word), frequency, shortcutTargets, null, true /* isShortcutOnly */); + } + + /** * Add a word to this dictionary. * - * The bigrams, if any, have to be in the dictionary already. If they aren't, + * The shortcuts and bigrams, if any, have to be in the dictionary already. If they aren't, * an exception is thrown. * * @param word the word, as an int array. * @param frequency the frequency of the word, in the range [0..255]. + * @param shortcutTargets an optional list of shortcut targets for this word (null if none). * @param bigrams an optional list of bigrams for this word (null if none). + * @param isShortcutOnly whether this should be a shortcut only. */ - private void add(int[] word, int frequency, ArrayList<WeightedString> bigrams) { + private void add(final int[] word, final int frequency, + final ArrayList<WeightedString> shortcutTargets, + final ArrayList<WeightedString> bigrams, + final boolean isShortcutOnly) { assert(frequency >= 0 && frequency <= 255); Node currentNode = mRoot; int charIndex = 0; @@ -231,7 +285,8 @@ public class FusionDictionary implements Iterable<Word> { // No node at this point to accept the word. Create one. final int insertionIndex = findInsertionIndex(currentNode, word[charIndex]); final CharGroup newGroup = new CharGroup( - Arrays.copyOfRange(word, charIndex, word.length), bigrams, frequency); + Arrays.copyOfRange(word, charIndex, word.length), + shortcutTargets, bigrams, frequency, isShortcutOnly); currentNode.mData.add(insertionIndex, newGroup); checkStack(currentNode); } else { @@ -245,7 +300,8 @@ public class FusionDictionary implements Iterable<Word> { + new String(word, 0, word.length)); } else { final CharGroup newNode = new CharGroup(currentGroup.mChars, - bigrams, frequency, currentGroup.mChildren); + shortcutTargets, bigrams, frequency, currentGroup.mChildren, + isShortcutOnly); currentNode.mData.set(nodeIndex, newNode); checkStack(currentNode); } @@ -254,13 +310,13 @@ public class FusionDictionary implements Iterable<Word> { // We only have to create a new node and add it to the end of this. final CharGroup newNode = new CharGroup( Arrays.copyOfRange(word, charIndex + differentCharIndex, word.length), - bigrams, frequency); + shortcutTargets, bigrams, frequency, isShortcutOnly); currentGroup.mChildren = new Node(); currentGroup.mChildren.mData.add(newNode); } } else { if (0 == differentCharIndex) { - // Exact same word. Check the frequency is 0 or -1, and update. + // Exact same word. Check the frequency is 0 or NOT_A_TERMINAL, and update. if (0 != frequency) { if (0 < currentGroup.mFrequency) { throw new RuntimeException("This word already exists with frequency " @@ -268,7 +324,9 @@ public class FusionDictionary implements Iterable<Word> { + new String(word, 0, word.length)); } final CharGroup newGroup = new CharGroup(word, - currentGroup.mBigrams, frequency, currentGroup.mChildren); + currentGroup.mShortcutTargets, currentGroup.mBigrams, + frequency, currentGroup.mChildren, + currentGroup.mIsShortcutOnly && isShortcutOnly); currentNode.mData.set(nodeIndex, newGroup); } } else { @@ -277,22 +335,27 @@ public class FusionDictionary implements Iterable<Word> { Node newChildren = new Node(); final CharGroup newOldWord = new CharGroup( Arrays.copyOfRange(currentGroup.mChars, differentCharIndex, - currentGroup.mChars.length), - currentGroup.mBigrams, currentGroup.mFrequency, currentGroup.mChildren); + currentGroup.mChars.length), currentGroup.mShortcutTargets, + currentGroup.mBigrams, currentGroup.mFrequency, currentGroup.mChildren, + currentGroup.mIsShortcutOnly); newChildren.mData.add(newOldWord); final CharGroup newParent; if (charIndex + differentCharIndex >= word.length) { newParent = new CharGroup( Arrays.copyOfRange(currentGroup.mChars, 0, differentCharIndex), - bigrams, frequency, newChildren); + shortcutTargets, bigrams, frequency, newChildren, isShortcutOnly); } else { + // isShortcutOnly makes no sense for non-terminal nodes. The following node + // is non-terminal (frequency 0 in FusionDictionary representation) so we + // pass false for isShortcutOnly newParent = new CharGroup( Arrays.copyOfRange(currentGroup.mChars, 0, differentCharIndex), - null, -1, newChildren); + null, null, -1, newChildren, false /* isShortcutOnly */); final CharGroup newWord = new CharGroup( Arrays.copyOfRange(word, charIndex + differentCharIndex, - word.length), bigrams, frequency); + word.length), shortcutTargets, bigrams, frequency, + isShortcutOnly); final int addIndex = word[charIndex + differentCharIndex] > currentGroup.mChars[differentCharIndex] ? 1 : 0; newChildren.mData.add(addIndex, newWord); @@ -355,7 +418,8 @@ public class FusionDictionary implements Iterable<Word> { */ private static int findInsertionIndex(final Node node, int character) { final List data = node.mData; - final CharGroup reference = new CharGroup(new int[] { character }, null, 0); + final CharGroup reference = new CharGroup(new int[] { character }, null, null, 0, + false /* isShortcutOnly */); int result = Collections.binarySearch(data, reference, CHARGROUP_COMPARATOR); return result >= 0 ? result : -result - 1; } @@ -399,6 +463,16 @@ public class FusionDictionary implements Iterable<Word> { } /** + * Helper method to find out whether a word is in the dict or not. + */ + public boolean hasWord(final String s) { + if (null == s || "".equals(s)) { + throw new RuntimeException("Can't search for a null or empty string"); + } + return null != findWordInTree(mRoot, s); + } + + /** * Recursively count the number of character groups in a given branch of the trie. * * @param node the parent node. @@ -573,7 +647,8 @@ public class FusionDictionary implements Iterable<Word> { } if (currentGroup.mFrequency >= 0) return new Word(mCurrentString.toString(), currentGroup.mFrequency, - currentGroup.mBigrams); + currentGroup.mShortcutTargets, currentGroup.mBigrams, + currentGroup.mIsShortcutOnly); } else { mPositions.removeLast(); currentPos = mPositions.getLast(); diff --git a/tools/makedict/src/com/android/inputmethod/latin/Word.java b/tools/makedict/src/com/android/inputmethod/latin/Word.java index 916165a41..cf6116f91 100644 --- a/tools/makedict/src/com/android/inputmethod/latin/Word.java +++ b/tools/makedict/src/com/android/inputmethod/latin/Word.java @@ -28,12 +28,18 @@ import java.util.ArrayList; public class Word implements Comparable<Word> { final String mWord; final int mFrequency; + final boolean mIsShortcutOnly; + final ArrayList<WeightedString> mShortcutTargets; final ArrayList<WeightedString> mBigrams; - public Word(String word, int frequency, ArrayList<WeightedString> bigrams) { + public Word(final String word, final int frequency, + final ArrayList<WeightedString> shortcutTargets, + final ArrayList<WeightedString> bigrams, final boolean isShortcutOnly) { mWord = word; mFrequency = frequency; + mShortcutTargets = shortcutTargets; mBigrams = bigrams; + mIsShortcutOnly = isShortcutOnly; } /** @@ -60,6 +66,7 @@ public class Word implements Comparable<Word> { if (!(o instanceof Word)) return false; Word w = (Word)o; return mFrequency == w.mFrequency && mWord.equals(w.mWord) + && mShortcutTargets.equals(w.mShortcutTargets) && mBigrams.equals(w.mBigrams); } } diff --git a/tools/makedict/src/com/android/inputmethod/latin/XmlDictInputOutput.java b/tools/makedict/src/com/android/inputmethod/latin/XmlDictInputOutput.java index 35a7b51d6..77c536668 100644 --- a/tools/makedict/src/com/android/inputmethod/latin/XmlDictInputOutput.java +++ b/tools/makedict/src/com/android/inputmethod/latin/XmlDictInputOutput.java @@ -42,8 +42,12 @@ public class XmlDictInputOutput { private static final String WORD_TAG = "w"; private static final String BIGRAM_TAG = "bigram"; + private static final String SHORTCUT_TAG = "shortcut"; private static final String FREQUENCY_ATTR = "f"; private static final String WORD_ATTR = "word"; + private static final String SHORTCUT_ONLY_ATTR = "shortcutOnly"; + + private static final int SHORTCUT_ONLY_DEFAULT_FREQ = 1; /** * SAX handler for a unigram XML file. @@ -61,6 +65,7 @@ public class XmlDictInputOutput { int mState; // the state of the parser int mFreq; // the currently read freq String mWord; // the current word + final HashMap<String, ArrayList<WeightedString>> mShortcutsMap; final HashMap<String, ArrayList<WeightedString>> mBigramsMap; /** @@ -69,9 +74,11 @@ public class XmlDictInputOutput { * @param dict the dictionary to construct. * @param bigrams the bigrams as a map. This may be empty, but may not be null. */ - public UnigramHandler(FusionDictionary dict, - HashMap<String, ArrayList<WeightedString>> bigrams) { + public UnigramHandler(final FusionDictionary dict, + final HashMap<String, ArrayList<WeightedString>> shortcuts, + final HashMap<String, ArrayList<WeightedString>> bigrams) { mDictionary = dict; + mShortcutsMap = shortcuts; mBigramsMap = bigrams; mWord = ""; mState = START; @@ -107,47 +114,96 @@ public class XmlDictInputOutput { @Override public void endElement(String uri, String localName, String qName) { if (WORD == mState) { - mDictionary.add(mWord, mFreq, mBigramsMap.get(mWord)); + mDictionary.add(mWord, mFreq, mShortcutsMap.get(mWord), mBigramsMap.get(mWord)); mState = START; } } } + static private class AssociativeListHandler extends DefaultHandler { + private final String SRC_TAG; + private final String SRC_ATTRIBUTE; + private final String DST_TAG; + private final String DST_ATTRIBUTE; + private final String DST_FREQ; + + // In this version of the XML file, the bigram frequency is given as an int 0..XML_MAX + private final static int XML_MAX = 256; + // In memory and in the binary dictionary the bigram frequency is 0..MEMORY_MAX + private final static int MEMORY_MAX = 16; + private final static int XML_TO_MEMORY_RATIO = XML_MAX / MEMORY_MAX; + + private String mSrc; + private final HashMap<String, ArrayList<WeightedString>> mAssocMap; + + public AssociativeListHandler(final String srcTag, final String srcAttribute, + final String dstTag, final String dstAttribute, final String dstFreq) { + SRC_TAG = srcTag; + SRC_ATTRIBUTE = srcAttribute; + DST_TAG = dstTag; + DST_ATTRIBUTE = dstAttribute; + DST_FREQ = dstFreq; + mSrc = null; + mAssocMap = new HashMap<String, ArrayList<WeightedString>>(); + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attrs) { + if (SRC_TAG.equals(localName)) { + mSrc = attrs.getValue(uri, SRC_ATTRIBUTE); + } else if (DST_TAG.equals(localName)) { + String dst = attrs.getValue(uri, DST_ATTRIBUTE); + int freq = Integer.parseInt(attrs.getValue(uri, DST_FREQ)); + WeightedString bigram = new WeightedString(dst, freq / XML_TO_MEMORY_RATIO); + ArrayList<WeightedString> bigramList = mAssocMap.get(mSrc); + if (null == bigramList) bigramList = new ArrayList<WeightedString>(); + bigramList.add(bigram); + mAssocMap.put(mSrc, bigramList); + } + } + + public HashMap<String, ArrayList<WeightedString>> getAssocMap() { + return mAssocMap; + } + } + /** * SAX handler for a bigram XML file. */ - static private class BigramHandler extends DefaultHandler { + static private class BigramHandler extends AssociativeListHandler { private final static String BIGRAM_W1_TAG = "bi"; private final static String BIGRAM_W2_TAG = "w"; private final static String BIGRAM_W1_ATTRIBUTE = "w1"; private final static String BIGRAM_W2_ATTRIBUTE = "w2"; private final static String BIGRAM_FREQ_ATTRIBUTE = "p"; - String mW1; - final HashMap<String, ArrayList<WeightedString>> mBigramsMap; - public BigramHandler() { - mW1 = null; - mBigramsMap = new HashMap<String, ArrayList<WeightedString>>(); + super(BIGRAM_W1_TAG, BIGRAM_W1_ATTRIBUTE, BIGRAM_W2_TAG, BIGRAM_W2_ATTRIBUTE, + BIGRAM_FREQ_ATTRIBUTE); } - @Override - public void startElement(String uri, String localName, String qName, Attributes attrs) { - if (BIGRAM_W1_TAG.equals(localName)) { - mW1 = attrs.getValue(uri, BIGRAM_W1_ATTRIBUTE); - } else if (BIGRAM_W2_TAG.equals(localName)) { - String w2 = attrs.getValue(uri, BIGRAM_W2_ATTRIBUTE); - int freq = Integer.parseInt(attrs.getValue(uri, BIGRAM_FREQ_ATTRIBUTE)); - WeightedString bigram = new WeightedString(w2, freq / 8); - ArrayList<WeightedString> bigramList = mBigramsMap.get(mW1); - if (null == bigramList) bigramList = new ArrayList<WeightedString>(); - bigramList.add(bigram); - mBigramsMap.put(mW1, bigramList); - } + public HashMap<String, ArrayList<WeightedString>> getBigramMap() { + return getAssocMap(); } + } - public HashMap<String, ArrayList<WeightedString>> getBigramMap() { - return mBigramsMap; + /** + * SAX handler for a shortcut XML file. + */ + static private class ShortcutHandler extends AssociativeListHandler { + private final static String ENTRY_TAG = "entry"; + private final static String ENTRY_ATTRIBUTE = "shortcut"; + private final static String TARGET_TAG = "target"; + private final static String REPLACEMENT_ATTRIBUTE = "replacement"; + private final static String TARGET_PRIORITY_ATTRIBUTE = "priority"; + + public ShortcutHandler() { + super(ENTRY_TAG, ENTRY_ATTRIBUTE, TARGET_TAG, REPLACEMENT_ATTRIBUTE, + TARGET_PRIORITY_ATTRIBUTE); + } + + public HashMap<String, ArrayList<WeightedString>> getShortcutMap() { + return getAssocMap(); } } @@ -158,9 +214,12 @@ public class XmlDictInputOutput { * representation. * * @param unigrams the file to read the data from. + * @param shortcuts the file to read the shortcuts from, or null. + * @param bigrams the file to read the bigrams from, or null. * @return the in-memory representation of the dictionary. */ - public static FusionDictionary readDictionaryXml(InputStream unigrams, InputStream bigrams) + public static FusionDictionary readDictionaryXml(final InputStream unigrams, + final InputStream shortcuts, final InputStream bigrams) throws SAXException, IOException, ParserConfigurationException { final SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(true); @@ -168,10 +227,23 @@ public class XmlDictInputOutput { final BigramHandler bigramHandler = new BigramHandler(); if (null != bigrams) parser.parse(bigrams, bigramHandler); + final ShortcutHandler shortcutHandler = new ShortcutHandler(); + if (null != shortcuts) parser.parse(shortcuts, shortcutHandler); + final FusionDictionary dict = new FusionDictionary(); final UnigramHandler unigramHandler = - new UnigramHandler(dict, bigramHandler.getBigramMap()); + new UnigramHandler(dict, shortcutHandler.getShortcutMap(), + bigramHandler.getBigramMap()); parser.parse(unigrams, unigramHandler); + + final HashMap<String, ArrayList<WeightedString>> shortcutMap = + shortcutHandler.getShortcutMap(); + for (final String shortcut : shortcutMap.keySet()) { + if (dict.hasWord(shortcut)) continue; + // TODO: list a frequency in the shortcut file and use it here, instead of + // a constant freq + dict.addShortcutOnly(shortcut, SHORTCUT_ONLY_DEFAULT_FREQ, shortcutMap.get(shortcut)); + } return dict; } @@ -204,9 +276,20 @@ public class XmlDictInputOutput { } // TODO: use an XMLSerializer if this gets big destination.write("<wordlist format=\"2\">\n"); + destination.write("<!-- Warning: there is no code to read this format yet. -->\n"); for (Word word : set) { destination.write(" <" + WORD_TAG + " " + WORD_ATTR + "=\"" + word.mWord + "\" " - + FREQUENCY_ATTR + "=\"" + word.mFrequency + "\">"); + + FREQUENCY_ATTR + "=\"" + word.mFrequency + "\" " + SHORTCUT_ONLY_ATTR + + "=\"" + word.mIsShortcutOnly + "\">"); + if (null != word.mShortcutTargets) { + destination.write("\n"); + for (WeightedString target : word.mShortcutTargets) { + destination.write(" <" + SHORTCUT_TAG + " " + FREQUENCY_ATTR + "=\"" + + target.mFrequency + "\">" + target.mWord + "</" + SHORTCUT_TAG + + ">\n"); + } + destination.write(" "); + } if (null != word.mBigrams) { destination.write("\n"); for (WeightedString bigram : word.mBigrams) { diff --git a/tools/makedict/tests/com/android/inputmethod/latin/BinaryDictInputOutputTest.java b/tools/makedict/tests/com/android/inputmethod/latin/BinaryDictInputOutputTest.java index 79cf14b2b..6ac046bbf 100644 --- a/tools/makedict/tests/com/android/inputmethod/latin/BinaryDictInputOutputTest.java +++ b/tools/makedict/tests/com/android/inputmethod/latin/BinaryDictInputOutputTest.java @@ -39,11 +39,11 @@ public class BinaryDictInputOutputTest extends TestCase { // that it does not contain any duplicates. public void testFlattenNodes() { final FusionDictionary dict = new FusionDictionary(); - dict.add("foo", 1, null); - dict.add("fta", 1, null); - dict.add("ftb", 1, null); - dict.add("bar", 1, null); - dict.add("fool", 1, null); + dict.add("foo", 1, null, null); + dict.add("fta", 1, null, null); + dict.add("ftb", 1, null, null); + dict.add("bar", 1, null, null); + dict.add("fool", 1, null, null); final ArrayList<Node> result = BinaryDictInputOutput.flattenTree(dict.mRoot); assertEquals(4, result.size()); while (!result.isEmpty()) { |